diff --git a/bracket/bracket.go b/bracket/bracket.go index 528377f..7b7c241 100644 --- a/bracket/bracket.go +++ b/bracket/bracket.go @@ -8,6 +8,7 @@ package bracket import ( "fmt" "github.com/Team254/cheesy-arena-lite/model" + "sort" "time" ) @@ -176,6 +177,21 @@ func (bracket *Bracket) IsComplete() bool { return bracket.FinalsMatchup.isComplete() } +// Returns a slice of all matchups contained within the bracket. +func (bracket *Bracket) GetAllMatchups() []*Matchup { + var matchups []*Matchup + for _, matchup := range bracket.matchupMap { + matchups = append(matchups, matchup) + } + sort.Slice(matchups, func(i, j int) bool { + if matchups[i].Round == matchups[j].Round { + return matchups[i].Group < matchups[j].Group + } + return matchups[i].Round < matchups[j].Round + }) + return matchups +} + // Returns the matchup for the given round and group, or an error if it doesn't exist within the bracket. func (bracket *Bracket) GetMatchup(round, group int) (*Matchup, error) { matchupKey := newMatchupKey(round, group) diff --git a/bracket/bracket_test.go b/bracket/bracket_test.go index 31a3fe7..7b0f909 100644 --- a/bracket/bracket_test.go +++ b/bracket/bracket_test.go @@ -14,7 +14,7 @@ import ( func TestNewBracketErrors(t *testing.T) { _, err := newBracket([]matchupTemplate{}, newMatchupKey(33, 12), 8) if assert.NotNil(t, err) { - assert.Equal(t, "could not find template for matchup {round:33 group:12} in the list of templates", err.Error()) + assert.Equal(t, "could not find template for matchup {Round:33 Group:12} in the list of templates", err.Error()) } matchTemplate := matchupTemplate{ @@ -33,35 +33,35 @@ func TestNewBracketInverseSeeding(t *testing.T) { matchupTemplates := []matchupTemplate{ { matchupKey: newMatchupKey(1, 1), - displayNameFormat: "QF${group}-${instance}", + displayName: "QF1", NumWinsToAdvance: 2, redAllianceSource: allianceSource{allianceId: 8}, blueAllianceSource: allianceSource{allianceId: 1}, }, { matchupKey: newMatchupKey(1, 2), - displayNameFormat: "QF${group}-${instance}", + displayName: "QF2", NumWinsToAdvance: 2, redAllianceSource: allianceSource{allianceId: 5}, blueAllianceSource: allianceSource{allianceId: 4}, }, { matchupKey: newMatchupKey(2, 1), - displayNameFormat: "SF${group}-${instance}", + displayName: "SF1", NumWinsToAdvance: 2, redAllianceSource: newWinnerAllianceSource(1, 2), blueAllianceSource: newWinnerAllianceSource(1, 1), }, { matchupKey: newMatchupKey(2, 2), - displayNameFormat: "SF${group}-${instance}", + displayName: "SF2", NumWinsToAdvance: 2, redAllianceSource: allianceSource{allianceId: 3}, blueAllianceSource: allianceSource{allianceId: 2}, }, { matchupKey: newMatchupKey(3, 1), - displayNameFormat: "F-${instance}", + displayName: "F", NumWinsToAdvance: 2, redAllianceSource: newWinnerAllianceSource(2, 1), blueAllianceSource: newWinnerAllianceSource(2, 2), @@ -170,6 +170,23 @@ func TestBracketUpdateTeamPositions(t *testing.T) { } } +func TestBracketGetAllMatchups(t *testing.T) { + database := setupTestDb(t) + + tournament.CreateTestAlliances(database, 5) + bracket, err := NewSingleEliminationBracket(5) + assert.Nil(t, err) + assert.Nil(t, bracket.Update(database, &dummyStartTime)) + + matchups := bracket.GetAllMatchups() + if assert.Equal(t, 4, len(matchups)) { + assert.Equal(t, newMatchupKey(2, 2), matchups[0].matchupKey) + assert.Equal(t, newMatchupKey(3, 1), matchups[1].matchupKey) + assert.Equal(t, newMatchupKey(3, 2), matchups[2].matchupKey) + assert.Equal(t, newMatchupKey(4, 1), matchups[3].matchupKey) + } +} + func TestBracketGetMatchup(t *testing.T) { database := setupTestDb(t) @@ -188,7 +205,7 @@ func TestBracketGetMatchup(t *testing.T) { matchup, err = bracket.GetMatchup(2, 1) if assert.NotNil(t, err) { - assert.Equal(t, "bracket does not contain matchup for key {round:2 group:1}", err.Error()) + assert.Equal(t, "bracket does not contain matchup for key {Round:2 Group:1}", err.Error()) } assert.Nil(t, matchup) } diff --git a/bracket/double_elimination.go b/bracket/double_elimination.go index 04c2a5c..d7a992a 100644 --- a/bracket/double_elimination.go +++ b/bracket/double_elimination.go @@ -18,98 +18,98 @@ func NewDoubleEliminationBracket(numAlliances int) (*Bracket, error) { var doubleEliminationBracketMatchupTemplates = []matchupTemplate{ { matchupKey: newMatchupKey(1, 1), - displayNameFormat: "1", + displayName: "1", NumWinsToAdvance: 1, redAllianceSource: allianceSource{allianceId: 1}, blueAllianceSource: allianceSource{allianceId: 8}, }, { matchupKey: newMatchupKey(1, 2), - displayNameFormat: "2", + displayName: "2", NumWinsToAdvance: 1, redAllianceSource: allianceSource{allianceId: 4}, blueAllianceSource: allianceSource{allianceId: 5}, }, { matchupKey: newMatchupKey(1, 3), - displayNameFormat: "3", + displayName: "3", NumWinsToAdvance: 1, redAllianceSource: allianceSource{allianceId: 3}, blueAllianceSource: allianceSource{allianceId: 6}, }, { matchupKey: newMatchupKey(1, 4), - displayNameFormat: "4", + displayName: "4", NumWinsToAdvance: 1, redAllianceSource: allianceSource{allianceId: 2}, blueAllianceSource: allianceSource{allianceId: 7}, }, { matchupKey: newMatchupKey(2, 1), - displayNameFormat: "5", + displayName: "5", NumWinsToAdvance: 1, redAllianceSource: newLoserAllianceSource(1, 1), blueAllianceSource: newLoserAllianceSource(1, 2), }, { matchupKey: newMatchupKey(2, 2), - displayNameFormat: "6", + displayName: "6", NumWinsToAdvance: 1, redAllianceSource: newLoserAllianceSource(1, 3), blueAllianceSource: newLoserAllianceSource(1, 4), }, { matchupKey: newMatchupKey(2, 3), - displayNameFormat: "7", + displayName: "7", NumWinsToAdvance: 1, redAllianceSource: newWinnerAllianceSource(1, 1), blueAllianceSource: newWinnerAllianceSource(1, 2), }, { matchupKey: newMatchupKey(2, 4), - displayNameFormat: "8", + displayName: "8", NumWinsToAdvance: 1, redAllianceSource: newWinnerAllianceSource(1, 3), blueAllianceSource: newWinnerAllianceSource(1, 4), }, { matchupKey: newMatchupKey(3, 1), - displayNameFormat: "9", + displayName: "9", NumWinsToAdvance: 1, redAllianceSource: newLoserAllianceSource(2, 3), blueAllianceSource: newWinnerAllianceSource(2, 2), }, { matchupKey: newMatchupKey(3, 2), - displayNameFormat: "10", + displayName: "10", NumWinsToAdvance: 1, redAllianceSource: newLoserAllianceSource(2, 4), blueAllianceSource: newWinnerAllianceSource(2, 1), }, { matchupKey: newMatchupKey(4, 1), - displayNameFormat: "11", + displayName: "11", NumWinsToAdvance: 1, redAllianceSource: newWinnerAllianceSource(3, 1), blueAllianceSource: newWinnerAllianceSource(3, 2), }, { matchupKey: newMatchupKey(4, 2), - displayNameFormat: "12", + displayName: "12", NumWinsToAdvance: 1, redAllianceSource: newWinnerAllianceSource(2, 3), blueAllianceSource: newWinnerAllianceSource(2, 4), }, { matchupKey: newMatchupKey(5, 1), - displayNameFormat: "13", + displayName: "13", NumWinsToAdvance: 1, redAllianceSource: newLoserAllianceSource(4, 2), blueAllianceSource: newWinnerAllianceSource(4, 1), }, { matchupKey: newMatchupKey(6, 1), - displayNameFormat: "F-${instance}", + displayName: "F", NumWinsToAdvance: 2, redAllianceSource: newWinnerAllianceSource(4, 2), blueAllianceSource: newWinnerAllianceSource(5, 1), diff --git a/bracket/matchup.go b/bracket/matchup.go index 672cb29..9de1776 100644 --- a/bracket/matchup.go +++ b/bracket/matchup.go @@ -10,7 +10,6 @@ import ( "fmt" "github.com/Team254/cheesy-arena-lite/model" "strconv" - "strings" ) // Conveys how a given alliance should be populated -- either directly from alliance selection or based on the results @@ -24,8 +23,8 @@ type allianceSource struct { // Key for uniquely identifying a matchup. Round IDs are arbitrary and in descending order with "1" always representing // the playoff finals. Group IDs are 1-indexed within a round and increasing in order of play. type matchupKey struct { - round int - group int + Round int + Group int } // Conveys the complete generic information about a matchup required to construct it. In aggregate, the full list of @@ -33,7 +32,7 @@ type matchupKey struct { // alliances. type matchupTemplate struct { matchupKey - displayNameFormat string + displayName string NumWinsToAdvance int redAllianceSource allianceSource blueAllianceSource allianceSource @@ -63,23 +62,78 @@ func newLoserAllianceSource(round, group int) allianceSource { // Convenience method to quickly create a matchup key. func newMatchupKey(round, group int) matchupKey { - return matchupKey{round: round, group: group} + return matchupKey{Round: round, Group: group} } // Returns the display name for a specific match within a matchup. -func (matchupTemplate *matchupTemplate) displayName(instance int) string { - displayName := matchupTemplate.displayNameFormat - displayName = strings.Replace(displayName, "${group}", strconv.Itoa(matchupTemplate.group), -1) - if strings.Contains(displayName, "${instance}") { - displayName = strings.Replace(displayName, "${instance}", strconv.Itoa(instance), -1) - } else if instance > 1 { - // Special case to handle matchups that only have more than one instance under exceptional circumstances (like - // ties in double-elimination unresolved by tiebreakers). +func (matchupTemplate *matchupTemplate) matchDisplayName(instance int) string { + displayName := matchupTemplate.displayName + if matchupTemplate.NumWinsToAdvance > 1 || instance > 1 { + // Append the instance if there is always more than one match in the series, or in exceptional circumstances + // like a tie in double-elimination unresolved by tiebreakers. displayName += fmt.Sprintf("-%d", instance) } return displayName } +// Returns the display name for the overall matchup. +func (matchup *Matchup) LongDisplayName() string { + if matchup.isFinal() { + return "Finals" + } + if _, err := strconv.Atoi(matchup.displayName); err == nil { + return "Match " + matchup.displayName + } + return matchup.displayName +} + +// Returns the display name for the linked matchup from which the red alliance is populated. +func (matchup *Matchup) RedAllianceSourceDisplayName() string { + if matchup.redAllianceSourceMatchup == nil { + return "" + } + if matchup.redAllianceSource.useWinner { + return "W " + matchup.redAllianceSourceMatchup.displayName + } + return "L " + matchup.redAllianceSourceMatchup.displayName +} + +// Returns the display name for the linked matchup from which the blue alliance is populated. +func (matchup *Matchup) BlueAllianceSourceDisplayName() string { + if matchup.blueAllianceSourceMatchup == nil { + return "" + } + if matchup.blueAllianceSource.useWinner { + return "W " + matchup.blueAllianceSourceMatchup.displayName + } + return "L " + matchup.blueAllianceSourceMatchup.displayName +} + +// Returns a pair of strings indicating the leading alliance and a readable status of the matchup. +func (matchup *Matchup) StatusText() (string, string) { + var leader, status string + winText := "Advances" + if matchup.isFinal() { + winText = "Wins" + } + if matchup.RedAllianceWins >= matchup.NumWinsToAdvance { + leader = "red" + status = fmt.Sprintf("Red %s %d-%d", winText, matchup.RedAllianceWins, matchup.BlueAllianceWins) + } else if matchup.BlueAllianceWins >= matchup.NumWinsToAdvance { + leader = "blue" + status = fmt.Sprintf("Blue %s %d-%d", winText, matchup.BlueAllianceWins, matchup.RedAllianceWins) + } else if matchup.RedAllianceWins > matchup.BlueAllianceWins { + leader = "red" + status = fmt.Sprintf("Red Leads %d-%d", matchup.RedAllianceWins, matchup.BlueAllianceWins) + } else if matchup.BlueAllianceWins > matchup.RedAllianceWins { + leader = "blue" + status = fmt.Sprintf("Blue Leads %d-%d", matchup.BlueAllianceWins, matchup.RedAllianceWins) + } else if matchup.RedAllianceWins > 0 { + status = fmt.Sprintf("Series Tied %d-%d", matchup.RedAllianceWins, matchup.BlueAllianceWins) + } + return leader, status +} + // Returns the winning alliance ID of the matchup, or 0 if it is not yet known. func (matchup *Matchup) winner() int { if matchup.RedAllianceWins >= matchup.NumWinsToAdvance { @@ -107,6 +161,11 @@ func (matchup *Matchup) isComplete() bool { return matchup.winner() > 0 } +// Returns true if the matchup represents the final matchup in the bracket. +func (matchup *Matchup) isFinal() bool { + return matchup.displayName == "F" +} + // Recursively traverses the matchup graph to update the state of this matchup and all of its children based on match // results, counting wins and creating or deleting matches as required. func (matchup *Matchup) update(database *model.Database) error { @@ -138,7 +197,7 @@ func (matchup *Matchup) update(database *model.Database) error { } } - matches, err := database.GetMatchesByElimRoundGroup(matchup.round, matchup.group) + matches, err := database.GetMatchesByElimRoundGroup(matchup.Round, matchup.Group) if err != nil { return err } @@ -164,10 +223,16 @@ func (matchup *Matchup) update(database *model.Database) error { if err != nil { return err } + if redAlliance == nil { + return fmt.Errorf("alliance %d does not exist in the database", matchup.RedAllianceId) + } blueAlliance, err := database.GetAllianceById(matchup.BlueAllianceId) if err != nil { return err } + if blueAlliance == nil { + return fmt.Errorf("alliance %d does not exist in the database", matchup.BlueAllianceId) + } matchup.RedAllianceWins = 0 matchup.BlueAllianceWins = 0 var unplayedMatches []model.Match @@ -226,9 +291,9 @@ func (matchup *Matchup) update(database *model.Database) error { instance := len(matches) + i + 1 match := model.Match{ Type: "elimination", - DisplayName: matchup.displayName(instance), - ElimRound: matchup.round, - ElimGroup: matchup.group, + DisplayName: matchup.matchDisplayName(instance), + ElimRound: matchup.Round, + ElimGroup: matchup.Group, ElimInstance: instance, ElimRedAlliance: redAlliance.Id, ElimBlueAlliance: blueAlliance.Id, diff --git a/bracket/matchup_test.go b/bracket/matchup_test.go new file mode 100644 index 0000000..8cb1cfb --- /dev/null +++ b/bracket/matchup_test.go @@ -0,0 +1,99 @@ +// Copyright 2022 Team 254. All Rights Reserved. +// Author: pat@patfairbank.com (Patrick Fairbank) + +package bracket + +import ( + "github.com/Team254/cheesy-arena-lite/tournament" + "github.com/stretchr/testify/assert" + "testing" +) + +func TestMatchupDisplayNames(t *testing.T) { + database := setupTestDb(t) + tournament.CreateTestAlliances(database, 8) + bracket, err := NewDoubleEliminationBracket(8) + assert.Nil(t, err) + + assert.Equal(t, "Finals", bracket.FinalsMatchup.LongDisplayName()) + assert.Equal(t, "F-1", bracket.FinalsMatchup.matchDisplayName(1)) + assert.Equal(t, "W 12", bracket.FinalsMatchup.RedAllianceSourceDisplayName()) + assert.Equal(t, "W 13", bracket.FinalsMatchup.BlueAllianceSourceDisplayName()) + + match13, err := bracket.GetMatchup(5, 1) + assert.Nil(t, err) + assert.Equal(t, "Match 13", match13.LongDisplayName()) + assert.Equal(t, "13", match13.matchDisplayName(1)) + assert.Equal(t, "13-2", match13.matchDisplayName(2)) + assert.Equal(t, "L 12", match13.RedAllianceSourceDisplayName()) + assert.Equal(t, "W 11", match13.BlueAllianceSourceDisplayName()) + + bracket, err = NewSingleEliminationBracket(8) + assert.Nil(t, err) + + assert.Equal(t, "Finals", bracket.FinalsMatchup.LongDisplayName()) + assert.Equal(t, "F-1", bracket.FinalsMatchup.matchDisplayName(1)) + assert.Equal(t, "W SF1", bracket.FinalsMatchup.RedAllianceSourceDisplayName()) + assert.Equal(t, "W SF2", bracket.FinalsMatchup.BlueAllianceSourceDisplayName()) + + matchSf2, err := bracket.GetMatchup(3, 2) + assert.Nil(t, err) + assert.Equal(t, "SF2", matchSf2.LongDisplayName()) + assert.Equal(t, "SF2-1", matchSf2.matchDisplayName(1)) + assert.Equal(t, "SF2-3", matchSf2.matchDisplayName(3)) + assert.Equal(t, "W QF3", matchSf2.RedAllianceSourceDisplayName()) + assert.Equal(t, "W QF4", matchSf2.BlueAllianceSourceDisplayName()) +} + +func TestMatchupStatusText(t *testing.T) { + matchup := Matchup{matchupTemplate: matchupTemplate{NumWinsToAdvance: 1}} + + leader, status := matchup.StatusText() + assert.Equal(t, "", leader) + assert.Equal(t, "", status) + + matchup.RedAllianceWins = 1 + leader, status = matchup.StatusText() + assert.Equal(t, "red", leader) + assert.Equal(t, "Red Advances 1-0", status) + + matchup.RedAllianceWins = 0 + matchup.BlueAllianceWins = 2 + leader, status = matchup.StatusText() + assert.Equal(t, "blue", leader) + assert.Equal(t, "Blue Advances 2-0", status) + + matchup.NumWinsToAdvance = 3 + matchup.BlueAllianceWins = 2 + leader, status = matchup.StatusText() + assert.Equal(t, "blue", leader) + assert.Equal(t, "Blue Leads 2-0", status) + + matchup.RedAllianceWins = 2 + leader, status = matchup.StatusText() + assert.Equal(t, "", leader) + assert.Equal(t, "Series Tied 2-2", status) + + matchup.BlueAllianceWins = 1 + leader, status = matchup.StatusText() + assert.Equal(t, "red", leader) + assert.Equal(t, "Red Leads 2-1", status) + + matchup.displayName = "F" + matchup.RedAllianceWins = 3 + leader, status = matchup.StatusText() + assert.Equal(t, "red", leader) + assert.Equal(t, "Red Wins 3-1", status) + + matchup.RedAllianceWins = 2 + matchup.BlueAllianceWins = 4 + leader, status = matchup.StatusText() + assert.Equal(t, "blue", leader) + assert.Equal(t, "Blue Wins 4-2", status) + + matchup.RedAllianceWins = 0 + matchup.BlueAllianceWins = 0 + leader, status = matchup.StatusText() + assert.Equal(t, "", leader) + assert.Equal(t, "", status) +} diff --git a/bracket/single_elimination.go b/bracket/single_elimination.go index 25dea78..bb42054 100644 --- a/bracket/single_elimination.go +++ b/bracket/single_elimination.go @@ -22,105 +22,105 @@ func NewSingleEliminationBracket(numAlliances int) (*Bracket, error) { var singleEliminationBracketMatchupTemplates = []matchupTemplate{ { matchupKey: newMatchupKey(1, 1), - displayNameFormat: "EF${group}-${instance}", + displayName: "EF1", NumWinsToAdvance: 2, redAllianceSource: allianceSource{allianceId: 1}, blueAllianceSource: allianceSource{allianceId: 16}, }, { matchupKey: newMatchupKey(1, 2), - displayNameFormat: "EF${group}-${instance}", + displayName: "EF2", NumWinsToAdvance: 2, redAllianceSource: allianceSource{allianceId: 8}, blueAllianceSource: allianceSource{allianceId: 9}, }, { matchupKey: newMatchupKey(1, 3), - displayNameFormat: "EF${group}-${instance}", + displayName: "EF3", NumWinsToAdvance: 2, redAllianceSource: allianceSource{allianceId: 4}, blueAllianceSource: allianceSource{allianceId: 13}, }, { matchupKey: newMatchupKey(1, 4), - displayNameFormat: "EF${group}-${instance}", + displayName: "EF4", NumWinsToAdvance: 2, redAllianceSource: allianceSource{allianceId: 5}, blueAllianceSource: allianceSource{allianceId: 12}, }, { matchupKey: newMatchupKey(1, 5), - displayNameFormat: "EF${group}-${instance}", + displayName: "EF5", NumWinsToAdvance: 2, redAllianceSource: allianceSource{allianceId: 2}, blueAllianceSource: allianceSource{allianceId: 15}, }, { matchupKey: newMatchupKey(1, 6), - displayNameFormat: "EF${group}-${instance}", + displayName: "EF6", NumWinsToAdvance: 2, redAllianceSource: allianceSource{allianceId: 7}, blueAllianceSource: allianceSource{allianceId: 10}, }, { matchupKey: newMatchupKey(1, 7), - displayNameFormat: "EF${group}-${instance}", + displayName: "EF7", NumWinsToAdvance: 2, redAllianceSource: allianceSource{allianceId: 3}, blueAllianceSource: allianceSource{allianceId: 14}, }, { matchupKey: newMatchupKey(1, 8), - displayNameFormat: "EF${group}-${instance}", + displayName: "EF8", NumWinsToAdvance: 2, redAllianceSource: allianceSource{allianceId: 6}, blueAllianceSource: allianceSource{allianceId: 11}, }, { matchupKey: newMatchupKey(2, 1), - displayNameFormat: "QF${group}-${instance}", + displayName: "QF1", NumWinsToAdvance: 2, redAllianceSource: newWinnerAllianceSource(1, 1), blueAllianceSource: newWinnerAllianceSource(1, 2), }, { matchupKey: newMatchupKey(2, 2), - displayNameFormat: "QF${group}-${instance}", + displayName: "QF2", NumWinsToAdvance: 2, redAllianceSource: newWinnerAllianceSource(1, 3), blueAllianceSource: newWinnerAllianceSource(1, 4), }, { matchupKey: newMatchupKey(2, 3), - displayNameFormat: "QF${group}-${instance}", + displayName: "QF3", NumWinsToAdvance: 2, redAllianceSource: newWinnerAllianceSource(1, 5), blueAllianceSource: newWinnerAllianceSource(1, 6), }, { matchupKey: newMatchupKey(2, 4), - displayNameFormat: "QF${group}-${instance}", + displayName: "QF4", NumWinsToAdvance: 2, redAllianceSource: newWinnerAllianceSource(1, 7), blueAllianceSource: newWinnerAllianceSource(1, 8), }, { matchupKey: newMatchupKey(3, 1), - displayNameFormat: "SF${group}-${instance}", + displayName: "SF1", NumWinsToAdvance: 2, redAllianceSource: newWinnerAllianceSource(2, 1), blueAllianceSource: newWinnerAllianceSource(2, 2), }, { matchupKey: newMatchupKey(3, 2), - displayNameFormat: "SF${group}-${instance}", + displayName: "SF2", NumWinsToAdvance: 2, redAllianceSource: newWinnerAllianceSource(2, 3), blueAllianceSource: newWinnerAllianceSource(2, 4), }, { matchupKey: newMatchupKey(4, 1), - displayNameFormat: "F-${instance}", + displayName: "F", NumWinsToAdvance: 2, redAllianceSource: newWinnerAllianceSource(3, 1), blueAllianceSource: newWinnerAllianceSource(3, 2), diff --git a/field/arena.go b/field/arena.go index 05cc20c..4221088 100755 --- a/field/arena.go +++ b/field/arena.go @@ -176,33 +176,29 @@ func (arena *Arena) LoadSettings() error { // Constructs an empty playoff bracket in memory, based only on the number of alliances. func (arena *Arena) CreatePlayoffBracket() error { - alliances, err := arena.Database.GetAllAlliances() - if err != nil { - return err + var err error + switch arena.EventSettings.ElimType { + case "single": + arena.PlayoffBracket, err = bracket.NewSingleEliminationBracket(arena.EventSettings.NumElimAlliances) + case "double": + arena.PlayoffBracket, err = bracket.NewDoubleEliminationBracket(arena.EventSettings.NumElimAlliances) + default: + err = fmt.Errorf("Invalid playoff type: %v", arena.EventSettings.ElimType) } - if len(alliances) > 0 { - switch arena.EventSettings.ElimType { - case "single": - arena.PlayoffBracket, err = bracket.NewSingleEliminationBracket(len(alliances)) - case "double": - arena.PlayoffBracket, err = bracket.NewDoubleEliminationBracket(len(alliances)) - default: - err = fmt.Errorf("Invalid playoff type: %v", arena.EventSettings.ElimType) - } - if err != nil { - return err - } - } - return nil + return err } // Traverses the in-memory playoff bracket to populate alliances, create matches, and assess winners. Does nothing if // the bracket has not been created.are func (arena *Arena) UpdatePlayoffBracket(startTime *time.Time) error { - if arena.PlayoffBracket == nil { - return nil + alliances, err := arena.Database.GetAllAlliances() + if err != nil { + return err } - return arena.PlayoffBracket.Update(arena.Database, startTime) + if len(alliances) > 0 { + return arena.PlayoffBracket.Update(arena.Database, startTime) + } + return nil } // Sets up the arena for the given match. diff --git a/field/arena_notifiers.go b/field/arena_notifiers.go index 52e4b68..aee15e1 100755 --- a/field/arena_notifiers.go +++ b/field/arena_notifiers.go @@ -6,7 +6,6 @@ package field import ( - "fmt" "github.com/Team254/cheesy-arena-lite/bracket" "github.com/Team254/cheesy-arena-lite/game" "github.com/Team254/cheesy-arena-lite/model" @@ -197,21 +196,7 @@ func (arena *Arena) generateScorePostedMessage() interface{} { var matchup *bracket.Matchup if arena.SavedMatch.Type == "elimination" { matchup, _ = arena.PlayoffBracket.GetMatchup(arena.SavedMatch.ElimRound, arena.SavedMatch.ElimGroup) - if matchup.RedAllianceWins >= matchup.NumWinsToAdvance { - seriesStatus = fmt.Sprintf("Red Wins Series %d-%d", matchup.RedAllianceWins, matchup.BlueAllianceWins) - seriesLeader = "red" - } else if matchup.BlueAllianceWins >= matchup.NumWinsToAdvance { - seriesStatus = fmt.Sprintf("Blue Wins Series %d-%d", matchup.BlueAllianceWins, matchup.RedAllianceWins) - seriesLeader = "blue" - } else if matchup.RedAllianceWins > matchup.BlueAllianceWins { - seriesStatus = fmt.Sprintf("Red Leads Series %d-%d", matchup.RedAllianceWins, matchup.BlueAllianceWins) - seriesLeader = "red" - } else if matchup.BlueAllianceWins > matchup.RedAllianceWins { - seriesStatus = fmt.Sprintf("Blue Leads Series %d-%d", matchup.BlueAllianceWins, matchup.RedAllianceWins) - seriesLeader = "blue" - } else { - seriesStatus = fmt.Sprintf("Series Tied %d-%d", matchup.RedAllianceWins, matchup.BlueAllianceWins) - } + seriesLeader, seriesStatus = matchup.StatusText() } rankings := make(map[int]game.Ranking, len(arena.SavedRankings)) diff --git a/static/css/audience_display.css b/static/css/audience_display.css index 60a4087..74b3c03 100644 --- a/static/css/audience_display.css +++ b/static/css/audience_display.css @@ -440,17 +440,13 @@ html { } #bracket { position: fixed; - width: 1600px; - height: 700px; top: 0; bottom: 0; left: 0; right: 0; margin: auto auto; - border: 2px solid #333; z-index: 1; opacity: 0; - background-color: #fff; text-align: center; } #sponsor { diff --git a/static/js/audience_display.js b/static/js/audience_display.js index efa3127..50fc56b 100644 --- a/static/js/audience_display.js +++ b/static/js/audience_display.js @@ -31,7 +31,8 @@ const scoreMid = "135px"; const scoreOut = "210px"; const scoreFieldsOut = "40px"; const scoreLogoTop = "-350px"; -const bracketLogoTop = "-600px"; +const bracketLogoTop = "-780px"; +const bracketLogoScale = 0.75; // Handles a websocket message to change which screen is displayed. var handleAudienceDisplayMode = function(targetScreen) { @@ -142,6 +143,9 @@ var handleScorePosted = function(data) { $("#finalSeriesStatus").text(data.SeriesStatus); $("#finalSeriesStatus").attr("data-leader", data.SeriesLeader); $("#finalMatchName").text(data.MatchType + " " + data.Match.DisplayName); + + // Reload the bracket to reflect any changes. + $("#bracketSvg").attr("src", "/api/bracket/svg?v=" + new Date().getTime()); }; // Handles a websocket message to play a sound to signal match start/stop/etc. @@ -292,7 +296,7 @@ var transitionBracketToLogo = function(callback) { $("#bracket").transition({queue: false, opacity: 0}, 500, "ease", function(){ $("#bracket").hide(); }); - $(".blindsCenter.full").transition({queue: false, top: 0}, 625, "ease", callback); + $(".blindsCenter.full").transition({queue: false, top: 0, scale: 1}, 625, "ease", callback); }; var transitionBracketToLogoLuma = function(callback) { @@ -302,7 +306,7 @@ var transitionBracketToLogoLuma = function(callback) { }; var transitionBracketToScore = function(callback) { - $(".blindsCenter.full").transition({queue: false, top: scoreLogoTop}, 1000, "ease"); + $(".blindsCenter.full").transition({queue: false, top: scoreLogoTop, scale: 1}, 1000, "ease"); $("#bracket").transition({queue: false, opacity: 0}, 1000, "ease", function(){ $("#bracket").hide(); $("#finalScore").show(); @@ -369,7 +373,7 @@ var transitionLogoToBlank = function(callback) { }; var transitionLogoToBracket = function(callback) { - $(".blindsCenter.full").transition({queue: false, top: bracketLogoTop}, 625, "ease"); + $(".blindsCenter.full").transition({queue: false, top: bracketLogoTop, scale: bracketLogoScale}, 625, "ease"); $("#bracket").show(); $("#bracket").transition({queue: false, opacity: 1}, 1000, "ease", callback); }; @@ -462,7 +466,7 @@ var transitionScoreToBlank = function(callback) { }; var transitionScoreToBracket = function(callback) { - $(".blindsCenter.full").transition({queue: false, top: bracketLogoTop}, 1000, "ease"); + $(".blindsCenter.full").transition({queue: false, top: bracketLogoTop, scale: bracketLogoScale}, 1000, "ease"); $("#finalScore").transition({queue: false, opacity: 0}, 1000, "ease", function(){ $("#finalScore").hide(); $("#bracket").show(); diff --git a/templates/audience_display.html b/templates/audience_display.html index 18aa0ac..f051ec2 100644 --- a/templates/audience_display.html +++ b/templates/audience_display.html @@ -107,7 +107,9 @@
- +