mirror of
https://github.com/Team254/cheesy-arena-lite.git
synced 2026-03-09 13:46:44 -04:00
Persist team substitutions in practice and playoff matches.
This commit is contained in:
@@ -258,6 +258,10 @@ func (arena *Arena) SubstituteTeam(teamId int, station string) error {
|
|||||||
}
|
}
|
||||||
arena.setupNetwork()
|
arena.setupNetwork()
|
||||||
arena.MatchLoadTeamsNotifier.Notify(nil)
|
arena.MatchLoadTeamsNotifier.Notify(nil)
|
||||||
|
|
||||||
|
if arena.CurrentMatch.Type != "test" {
|
||||||
|
arena.Database.SaveMatch(arena.CurrentMatch)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,21 +15,21 @@ import (
|
|||||||
const ElimMatchSpacingSec = 600
|
const ElimMatchSpacingSec = 600
|
||||||
|
|
||||||
// Incrementally creates any elimination matches that can be created, based on the results of alliance
|
// Incrementally creates any elimination matches that can be created, based on the results of alliance
|
||||||
// selection or prior elimination rounds. Returns the winning alliance once it has been determined.
|
// selection or prior elimination rounds. Returns true if the tournament is won.
|
||||||
func UpdateEliminationSchedule(database *model.Database, startTime time.Time) ([]model.AllianceTeam, error) {
|
func UpdateEliminationSchedule(database *model.Database, startTime time.Time) (bool, error) {
|
||||||
alliances, err := database.GetAllAlliances()
|
alliances, err := database.GetAllAlliances()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []model.AllianceTeam{}, err
|
return false, err
|
||||||
}
|
}
|
||||||
winner, err := buildEliminationMatchSet(database, 1, 1, len(alliances))
|
winner, err := buildEliminationMatchSet(database, 1, 1, len(alliances))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []model.AllianceTeam{}, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the scheduled time for all matches that have yet to be run.
|
// Update the scheduled time for all matches that have yet to be run.
|
||||||
matches, err := database.GetMatchesByType("elimination")
|
matches, err := database.GetMatchesByType("elimination")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []model.AllianceTeam{}, err
|
return false, err
|
||||||
}
|
}
|
||||||
matchIndex := 0
|
matchIndex := 0
|
||||||
for _, match := range matches {
|
for _, match := range matches {
|
||||||
@@ -41,25 +41,25 @@ func UpdateEliminationSchedule(database *model.Database, startTime time.Time) ([
|
|||||||
matchIndex++
|
matchIndex++
|
||||||
}
|
}
|
||||||
|
|
||||||
return winner, err
|
return len(winner) > 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursively traverses the elimination bracket downwards, creating matches as necessary. Returns the winner
|
// Recursively traverses the elimination bracket downwards, creating matches as necessary. Returns the winner
|
||||||
// of the given round if known.
|
// of the given round if known.
|
||||||
func buildEliminationMatchSet(database *model.Database, round int, group int, numAlliances int) ([]model.AllianceTeam, error) {
|
func buildEliminationMatchSet(database *model.Database, round int, group int, numAlliances int) ([]int, error) {
|
||||||
if numAlliances < 2 {
|
if numAlliances < 2 {
|
||||||
return []model.AllianceTeam{}, fmt.Errorf("Must have at least 2 alliances")
|
return []int{}, fmt.Errorf("Must have at least 2 alliances")
|
||||||
}
|
}
|
||||||
roundName, ok := model.ElimRoundNames[round]
|
roundName, ok := model.ElimRoundNames[round]
|
||||||
if !ok {
|
if !ok {
|
||||||
return []model.AllianceTeam{}, fmt.Errorf("Round of depth %d is not supported", round*2)
|
return []int{}, fmt.Errorf("Round of depth %d is not supported", round*2)
|
||||||
}
|
}
|
||||||
if round != 1 {
|
if round != 1 {
|
||||||
roundName += strconv.Itoa(group)
|
roundName += strconv.Itoa(group)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recurse to figure out who the involved alliances are.
|
// Recurse to figure out who the involved alliances are.
|
||||||
var redAlliance, blueAlliance []model.AllianceTeam
|
var redAlliance, blueAlliance []int
|
||||||
var err error
|
var err error
|
||||||
if numAlliances < 4*round {
|
if numAlliances < 4*round {
|
||||||
// This is the first round for some or all alliances and will be at least partially populated from the
|
// This is the first round for some or all alliances and will be at least partially populated from the
|
||||||
@@ -71,16 +71,32 @@ func buildEliminationMatchSet(database *model.Database, round int, group int, nu
|
|||||||
numDirectAlliances := 4*round - numAlliances
|
numDirectAlliances := 4*round - numAlliances
|
||||||
if redAllianceNumber <= numDirectAlliances {
|
if redAllianceNumber <= numDirectAlliances {
|
||||||
// The red alliance has a bye or the number of alliances is a power of 2; get from alliance selection.
|
// The red alliance has a bye or the number of alliances is a power of 2; get from alliance selection.
|
||||||
redAlliance, err = database.GetTeamsByAlliance(redAllianceNumber)
|
redAllianceTeams, err := database.GetTeamsByAlliance(redAllianceNumber)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []model.AllianceTeam{}, err
|
return []int{}, err
|
||||||
|
}
|
||||||
|
for _, allianceTeam := range redAllianceTeams {
|
||||||
|
redAlliance = append(redAlliance, allianceTeam.TeamId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(redAlliance) >= 3 {
|
||||||
|
// Swap the teams around to match the positions dictated by the 2017 rules.
|
||||||
|
redAlliance[0], redAlliance[1], redAlliance[2] = redAlliance[2], redAlliance[0], redAlliance[1]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if blueAllianceNumber <= numDirectAlliances {
|
if blueAllianceNumber <= numDirectAlliances {
|
||||||
// The blue alliance has a bye or the number of alliances is a power of 2; get from alliance selection.
|
// The blue alliance has a bye or the number of alliances is a power of 2; get from alliance selection.
|
||||||
blueAlliance, err = database.GetTeamsByAlliance(blueAllianceNumber)
|
blueAllianceTeams, err := database.GetTeamsByAlliance(blueAllianceNumber)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []model.AllianceTeam{}, err
|
return []int{}, err
|
||||||
|
}
|
||||||
|
for _, allianceTeam := range blueAllianceTeams {
|
||||||
|
blueAlliance = append(blueAlliance, allianceTeam.TeamId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(blueAlliance) >= 3 {
|
||||||
|
// Swap the teams around to match the positions dictated by the 2017 rules.
|
||||||
|
blueAlliance[0], blueAlliance[1], blueAlliance[2] = blueAlliance[1], blueAlliance[0], blueAlliance[2]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,19 +105,19 @@ func buildEliminationMatchSet(database *model.Database, round int, group int, nu
|
|||||||
if len(redAlliance) == 0 {
|
if len(redAlliance) == 0 {
|
||||||
redAlliance, err = buildEliminationMatchSet(database, round*2, group*2-1, numAlliances)
|
redAlliance, err = buildEliminationMatchSet(database, round*2, group*2-1, numAlliances)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []model.AllianceTeam{}, err
|
return []int{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(blueAlliance) == 0 {
|
if len(blueAlliance) == 0 {
|
||||||
blueAlliance, err = buildEliminationMatchSet(database, round*2, group*2, numAlliances)
|
blueAlliance, err = buildEliminationMatchSet(database, round*2, group*2, numAlliances)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []model.AllianceTeam{}, err
|
return []int{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bail if the rounds below are not yet complete and we don't know either alliance competing this round.
|
// Bail if the rounds below are not yet complete and we don't know either alliance competing this round.
|
||||||
if len(redAlliance) == 0 && len(blueAlliance) == 0 {
|
if len(redAlliance) == 0 && len(blueAlliance) == 0 {
|
||||||
return []model.AllianceTeam{}, nil
|
return []int{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the match set exists already and if it has been won.
|
// Check if the match set exists already and if it has been won.
|
||||||
@@ -109,27 +125,38 @@ func buildEliminationMatchSet(database *model.Database, round int, group int, nu
|
|||||||
var ties []*model.Match
|
var ties []*model.Match
|
||||||
matches, err := database.GetMatchesByElimRoundGroup(round, group)
|
matches, err := database.GetMatchesByElimRoundGroup(round, group)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []model.AllianceTeam{}, err
|
return []int{}, err
|
||||||
}
|
}
|
||||||
var unplayedMatches []*model.Match
|
var unplayedMatches []*model.Match
|
||||||
for _, match := range matches {
|
for _, match := range matches {
|
||||||
// Update the teams in the match if they are not yet set or are incorrect.
|
|
||||||
if len(redAlliance) != 0 && !(teamInAlliance(match.Red1, redAlliance) &&
|
|
||||||
teamInAlliance(match.Red2, redAlliance) && teamInAlliance(match.Red3, redAlliance)) {
|
|
||||||
positionRedTeams(&match, redAlliance)
|
|
||||||
database.SaveMatch(&match)
|
|
||||||
} else if len(blueAlliance) != 0 && !(teamInAlliance(match.Blue1, blueAlliance) &&
|
|
||||||
teamInAlliance(match.Blue2, blueAlliance) && teamInAlliance(match.Blue3, blueAlliance)) {
|
|
||||||
positionBlueTeams(&match, blueAlliance)
|
|
||||||
database.SaveMatch(&match)
|
|
||||||
}
|
|
||||||
|
|
||||||
if match.Status != "complete" {
|
if match.Status != "complete" {
|
||||||
|
// Update the teams in the match if they are not yet set or are incorrect.
|
||||||
|
if len(redAlliance) != 0 && !(match.Red1 == redAlliance[0] && match.Red2 == redAlliance[1] &&
|
||||||
|
match.Red3 == redAlliance[2]) {
|
||||||
|
positionRedTeams(&match, redAlliance)
|
||||||
|
database.SaveMatch(&match)
|
||||||
|
}
|
||||||
|
if len(blueAlliance) != 0 && !(match.Blue1 == blueAlliance[0] && match.Blue2 == blueAlliance[1] &&
|
||||||
|
match.Blue3 == blueAlliance[2]) {
|
||||||
|
positionBlueTeams(&match, blueAlliance)
|
||||||
|
database.SaveMatch(&match)
|
||||||
|
}
|
||||||
|
|
||||||
unplayedMatches = append(unplayedMatches, &match)
|
unplayedMatches = append(unplayedMatches, &match)
|
||||||
numIncomplete += 1
|
numIncomplete += 1
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reorder the teams based on the last complete match, so that new and unplayed matches use the same positions.
|
||||||
|
err = reorderTeams(match.Red1, match.Red2, match.Red3, redAlliance)
|
||||||
|
if err != nil {
|
||||||
|
return []int{}, err
|
||||||
|
}
|
||||||
|
err = reorderTeams(match.Blue1, match.Blue2, match.Blue3, blueAlliance)
|
||||||
|
if err != nil {
|
||||||
|
return []int{}, err
|
||||||
|
}
|
||||||
|
|
||||||
// Check who won.
|
// Check who won.
|
||||||
switch match.Winner {
|
switch match.Winner {
|
||||||
case "R":
|
case "R":
|
||||||
@@ -139,8 +166,7 @@ func buildEliminationMatchSet(database *model.Database, round int, group int, nu
|
|||||||
case "T":
|
case "T":
|
||||||
ties = append(ties, &match)
|
ties = append(ties, &match)
|
||||||
default:
|
default:
|
||||||
return []model.AllianceTeam{}, fmt.Errorf("Completed match %d has invalid winner '%s'", match.Id,
|
return []int{}, fmt.Errorf("Completed match %d has invalid winner '%s'", match.Id, match.Winner)
|
||||||
match.Winner)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,7 +175,7 @@ func buildEliminationMatchSet(database *model.Database, round int, group int, nu
|
|||||||
for _, match := range unplayedMatches {
|
for _, match := range unplayedMatches {
|
||||||
err = database.DeleteMatch(match)
|
err = database.DeleteMatch(match)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []model.AllianceTeam{}, err
|
return []int{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,54 +192,50 @@ func buildEliminationMatchSet(database *model.Database, round int, group int, nu
|
|||||||
if len(matches) == 0 || len(ties) == 0 && numIncomplete == 0 {
|
if len(matches) == 0 || len(ties) == 0 && numIncomplete == 0 {
|
||||||
// Fill in zeroes if only one alliance is known.
|
// Fill in zeroes if only one alliance is known.
|
||||||
if len(redAlliance) == 0 {
|
if len(redAlliance) == 0 {
|
||||||
redAlliance = []model.AllianceTeam{{}, {}, {}}
|
redAlliance = []int{0, 0, 0}
|
||||||
} else if len(blueAlliance) == 0 {
|
} else if len(blueAlliance) == 0 {
|
||||||
blueAlliance = []model.AllianceTeam{{}, {}, {}}
|
blueAlliance = []int{0, 0, 0}
|
||||||
}
|
}
|
||||||
if len(redAlliance) < 3 || len(blueAlliance) < 3 {
|
if len(redAlliance) < 3 || len(blueAlliance) < 3 {
|
||||||
// Raise an error if the alliance selection process gave us less than 3 teams per alliance.
|
// Raise an error if the alliance selection process gave us less than 3 teams per alliance.
|
||||||
return []model.AllianceTeam{}, fmt.Errorf("Alliances must consist of at least 3 teams")
|
return []int{}, fmt.Errorf("Alliances must consist of at least 3 teams")
|
||||||
}
|
}
|
||||||
if len(matches) < 1 {
|
if len(matches) < 1 {
|
||||||
err = database.CreateMatch(createMatch(roundName, round, group, 1, redAlliance, blueAlliance))
|
err = database.CreateMatch(createMatch(roundName, round, group, 1, redAlliance, blueAlliance))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []model.AllianceTeam{}, err
|
return []int{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(matches) < 2 {
|
if len(matches) < 2 {
|
||||||
err = database.CreateMatch(createMatch(roundName, round, group, 2, redAlliance, blueAlliance))
|
err = database.CreateMatch(createMatch(roundName, round, group, 2, redAlliance, blueAlliance))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []model.AllianceTeam{}, err
|
return []int{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(matches) < 3 {
|
if len(matches) < 3 {
|
||||||
err = database.CreateMatch(createMatch(roundName, round, group, 3, redAlliance, blueAlliance))
|
err = database.CreateMatch(createMatch(roundName, round, group, 3, redAlliance, blueAlliance))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []model.AllianceTeam{}, err
|
return []int{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duplicate any ties if we have run out of matches. Don't change the team positions, so queueing
|
// Duplicate any ties if we have run out of matches.
|
||||||
// personnel can reuse any tied matches without having to print new schedules.
|
|
||||||
if numIncomplete == 0 {
|
if numIncomplete == 0 {
|
||||||
for index, tie := range ties {
|
for index := range ties {
|
||||||
match := createMatch(roundName, round, group, len(matches)+index+1, redAlliance, blueAlliance)
|
err = database.CreateMatch(createMatch(roundName, round, group, len(matches)+index+1, redAlliance,
|
||||||
match.Red1, match.Red2, match.Red3 = tie.Red1, tie.Red2, tie.Red3
|
blueAlliance))
|
||||||
match.Blue1, match.Blue2, match.Blue3 = tie.Blue1, tie.Blue2, tie.Blue3
|
|
||||||
err = database.CreateMatch(match)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []model.AllianceTeam{}, err
|
return []int{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return []model.AllianceTeam{}, nil
|
return []int{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a match at the given point in the elimination bracket and populates the teams.
|
// Creates a match at the given point in the elimination bracket and populates the teams.
|
||||||
func createMatch(roundName string, round int, group int, instance int, redAlliance []model.AllianceTeam,
|
func createMatch(roundName string, round int, group int, instance int, redAlliance, blueAlliance []int) *model.Match {
|
||||||
blueAlliance []model.AllianceTeam) *model.Match {
|
|
||||||
match := model.Match{Type: "elimination", DisplayName: fmt.Sprintf("%s-%d", roundName, instance),
|
match := model.Match{Type: "elimination", DisplayName: fmt.Sprintf("%s-%d", roundName, instance),
|
||||||
ElimRound: round, ElimGroup: group, ElimInstance: instance}
|
ElimRound: round, ElimGroup: group, ElimInstance: instance}
|
||||||
positionRedTeams(&match, redAlliance)
|
positionRedTeams(&match, redAlliance)
|
||||||
@@ -222,27 +244,34 @@ func createMatch(roundName string, round int, group int, instance int, redAllian
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Assigns the first three teams from the alliance into the red team slots for the match.
|
// Assigns the first three teams from the alliance into the red team slots for the match.
|
||||||
func positionRedTeams(match *model.Match, alliance []model.AllianceTeam) {
|
func positionRedTeams(match *model.Match, alliance []int) {
|
||||||
// For the 2015 game, the alliance captain is in the middle, first pick on the left, second on the right.
|
match.Red1 = alliance[0]
|
||||||
match.Red1 = alliance[1].TeamId
|
match.Red2 = alliance[1]
|
||||||
match.Red2 = alliance[0].TeamId
|
match.Red3 = alliance[2]
|
||||||
match.Red3 = alliance[2].TeamId
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assigns the first three teams from the alliance into the blue team slots for the match.
|
// Assigns the first three teams from the alliance into the blue team slots for the match.
|
||||||
func positionBlueTeams(match *model.Match, alliance []model.AllianceTeam) {
|
func positionBlueTeams(match *model.Match, alliance []int) {
|
||||||
// For the 2015 game, the alliance captain is in the middle, first pick on the left, second on the right.
|
match.Blue1 = alliance[0]
|
||||||
match.Blue1 = alliance[1].TeamId
|
match.Blue2 = alliance[1]
|
||||||
match.Blue2 = alliance[0].TeamId
|
match.Blue3 = alliance[2]
|
||||||
match.Blue3 = alliance[2].TeamId
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if the given team is part of the given alliance.
|
// Swaps the order of teams in the alliance to match the match positioning.
|
||||||
func teamInAlliance(teamId int, alliance []model.AllianceTeam) bool {
|
func reorderTeams(team1, team2, team3 int, alliance []int) error {
|
||||||
for _, allianceTeam := range alliance {
|
for i, team := range []int{team1, team2, team3} {
|
||||||
if teamId == allianceTeam.TeamId {
|
found := false
|
||||||
return true
|
for j, oldTeam := range alliance {
|
||||||
|
if team == oldTeam {
|
||||||
|
alliance[i], alliance[j] = alliance[j], alliance[i]
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
return fmt.Errorf("Team %d not found in alliance %v", team, alliance)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -515,23 +515,21 @@ func TestEliminationScheduleDetermineWinner(t *testing.T) {
|
|||||||
CreateTestAlliances(database, 2)
|
CreateTestAlliances(database, 2)
|
||||||
UpdateEliminationSchedule(database, time.Unix(0, 0))
|
UpdateEliminationSchedule(database, time.Unix(0, 0))
|
||||||
scoreMatch(database, "F-1", "T")
|
scoreMatch(database, "F-1", "T")
|
||||||
winner, err := UpdateEliminationSchedule(database, time.Unix(0, 0))
|
won, err := UpdateEliminationSchedule(database, time.Unix(0, 0))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Empty(t, winner)
|
assert.False(t, won)
|
||||||
matches, _ := database.GetMatchesByType("elimination")
|
matches, _ := database.GetMatchesByType("elimination")
|
||||||
assert.Equal(t, 3, len(matches))
|
assert.Equal(t, 3, len(matches))
|
||||||
scoreMatch(database, "F-2", "B")
|
scoreMatch(database, "F-2", "B")
|
||||||
winner, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
won, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Empty(t, winner)
|
assert.False(t, won)
|
||||||
matches, _ = database.GetMatchesByType("elimination")
|
matches, _ = database.GetMatchesByType("elimination")
|
||||||
assert.Equal(t, 3, len(matches))
|
assert.Equal(t, 3, len(matches))
|
||||||
scoreMatch(database, "F-3", "B")
|
scoreMatch(database, "F-3", "B")
|
||||||
winner, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
won, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
||||||
if assert.Nil(t, err) {
|
if assert.Nil(t, err) {
|
||||||
if assert.Equal(t, 3, len(winner)) {
|
assert.True(t, won)
|
||||||
assert.Equal(t, 2, winner[0].TeamId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
matches, _ = database.GetMatchesByType("elimination")
|
matches, _ = database.GetMatchesByType("elimination")
|
||||||
assert.Equal(t, 3, len(matches))
|
assert.Equal(t, 3, len(matches))
|
||||||
@@ -543,34 +541,32 @@ func TestEliminationScheduleDetermineWinner(t *testing.T) {
|
|||||||
CreateTestAlliances(database, 2)
|
CreateTestAlliances(database, 2)
|
||||||
UpdateEliminationSchedule(database, time.Unix(0, 0))
|
UpdateEliminationSchedule(database, time.Unix(0, 0))
|
||||||
scoreMatch(database, "F-1", "R")
|
scoreMatch(database, "F-1", "R")
|
||||||
winner, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
won, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Empty(t, winner)
|
assert.False(t, won)
|
||||||
matches, _ = database.GetMatchesByType("elimination")
|
matches, _ = database.GetMatchesByType("elimination")
|
||||||
assert.Equal(t, 3, len(matches))
|
assert.Equal(t, 3, len(matches))
|
||||||
scoreMatch(database, "F-2", "T")
|
scoreMatch(database, "F-2", "T")
|
||||||
winner, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
won, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Empty(t, winner)
|
assert.False(t, won)
|
||||||
matches, _ = database.GetMatchesByType("elimination")
|
matches, _ = database.GetMatchesByType("elimination")
|
||||||
assert.Equal(t, 3, len(matches))
|
assert.Equal(t, 3, len(matches))
|
||||||
scoreMatch(database, "F-3", "B")
|
scoreMatch(database, "F-3", "B")
|
||||||
winner, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
won, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Empty(t, winner)
|
assert.False(t, won)
|
||||||
matches, _ = database.GetMatchesByType("elimination")
|
matches, _ = database.GetMatchesByType("elimination")
|
||||||
assert.Equal(t, 4, len(matches))
|
assert.Equal(t, 4, len(matches))
|
||||||
assert.Equal(t, "F-4", matches[3].DisplayName)
|
assert.Equal(t, "F-4", matches[3].DisplayName)
|
||||||
scoreMatch(database, "F-4", "T")
|
scoreMatch(database, "F-4", "T")
|
||||||
winner, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
won, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Empty(t, winner)
|
assert.False(t, won)
|
||||||
scoreMatch(database, "F-5", "R")
|
scoreMatch(database, "F-5", "R")
|
||||||
winner, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
won, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
||||||
if assert.Nil(t, err) {
|
if assert.Nil(t, err) {
|
||||||
if assert.Equal(t, 3, len(winner)) {
|
assert.True(t, won)
|
||||||
assert.Equal(t, 1, winner[0].TeamId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
database.TruncateAllianceTeams()
|
database.TruncateAllianceTeams()
|
||||||
database.TruncateMatches()
|
database.TruncateMatches()
|
||||||
@@ -580,31 +576,29 @@ func TestEliminationScheduleDetermineWinner(t *testing.T) {
|
|||||||
CreateTestAlliances(database, 2)
|
CreateTestAlliances(database, 2)
|
||||||
UpdateEliminationSchedule(database, time.Unix(0, 0))
|
UpdateEliminationSchedule(database, time.Unix(0, 0))
|
||||||
scoreMatch(database, "F-1", "T")
|
scoreMatch(database, "F-1", "T")
|
||||||
winner, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
won, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Empty(t, winner)
|
assert.False(t, won)
|
||||||
matches, _ = database.GetMatchesByType("elimination")
|
matches, _ = database.GetMatchesByType("elimination")
|
||||||
assert.Equal(t, 3, len(matches))
|
assert.Equal(t, 3, len(matches))
|
||||||
scoreMatch(database, "F-2", "B")
|
scoreMatch(database, "F-2", "B")
|
||||||
winner, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
won, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Empty(t, winner)
|
assert.False(t, won)
|
||||||
matches, _ = database.GetMatchesByType("elimination")
|
matches, _ = database.GetMatchesByType("elimination")
|
||||||
assert.Equal(t, 3, len(matches))
|
assert.Equal(t, 3, len(matches))
|
||||||
scoreMatch(database, "F-3", "T")
|
scoreMatch(database, "F-3", "T")
|
||||||
winner, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
won, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Empty(t, winner)
|
assert.False(t, won)
|
||||||
matches, _ = database.GetMatchesByType("elimination")
|
matches, _ = database.GetMatchesByType("elimination")
|
||||||
assert.Equal(t, 5, len(matches))
|
assert.Equal(t, 5, len(matches))
|
||||||
assert.Equal(t, "F-4", matches[3].DisplayName)
|
assert.Equal(t, "F-4", matches[3].DisplayName)
|
||||||
assert.Equal(t, "F-5", matches[4].DisplayName)
|
assert.Equal(t, "F-5", matches[4].DisplayName)
|
||||||
scoreMatch(database, "F-4", "B")
|
scoreMatch(database, "F-4", "B")
|
||||||
winner, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
won, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
||||||
if assert.Nil(t, err) {
|
if assert.Nil(t, err) {
|
||||||
if assert.Equal(t, 3, len(winner)) {
|
assert.True(t, won)
|
||||||
assert.Equal(t, 2, winner[0].TeamId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
database.TruncateAllianceTeams()
|
database.TruncateAllianceTeams()
|
||||||
database.TruncateMatches()
|
database.TruncateMatches()
|
||||||
@@ -616,19 +610,17 @@ func TestEliminationScheduleDetermineWinner(t *testing.T) {
|
|||||||
scoreMatch(database, "F-1", "T")
|
scoreMatch(database, "F-1", "T")
|
||||||
scoreMatch(database, "F-2", "T")
|
scoreMatch(database, "F-2", "T")
|
||||||
scoreMatch(database, "F-3", "T")
|
scoreMatch(database, "F-3", "T")
|
||||||
winner, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
won, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
||||||
scoreMatch(database, "F-4", "T")
|
scoreMatch(database, "F-4", "T")
|
||||||
scoreMatch(database, "F-5", "T")
|
scoreMatch(database, "F-5", "T")
|
||||||
scoreMatch(database, "F-6", "T")
|
scoreMatch(database, "F-6", "T")
|
||||||
winner, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
won, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
||||||
scoreMatch(database, "F-7", "R")
|
scoreMatch(database, "F-7", "R")
|
||||||
scoreMatch(database, "F-8", "B")
|
scoreMatch(database, "F-8", "B")
|
||||||
scoreMatch(database, "F-9", "R")
|
scoreMatch(database, "F-9", "R")
|
||||||
winner, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
won, err = UpdateEliminationSchedule(database, time.Unix(0, 0))
|
||||||
if assert.Nil(t, err) {
|
if assert.Nil(t, err) {
|
||||||
if assert.Equal(t, 3, len(winner)) {
|
assert.True(t, won)
|
||||||
assert.Equal(t, 1, winner[0].TeamId)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -737,10 +729,62 @@ func TestEliminationScheduleTiming(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEliminationScheduleTeamPositions(t *testing.T) {
|
||||||
|
database := setupTestDb(t)
|
||||||
|
|
||||||
|
CreateTestAlliances(database, 4)
|
||||||
|
UpdateEliminationSchedule(database, time.Unix(1000, 0))
|
||||||
|
matches, _ := database.GetMatchesByType("elimination")
|
||||||
|
match1 := matches[0]
|
||||||
|
match2 := matches[1]
|
||||||
|
assert.Equal(t, 100, match1.Red1)
|
||||||
|
assert.Equal(t, 1, match1.Red2)
|
||||||
|
assert.Equal(t, 10, match1.Red3)
|
||||||
|
assert.Equal(t, 30, match2.Blue1)
|
||||||
|
assert.Equal(t, 3, match2.Blue2)
|
||||||
|
assert.Equal(t, 300, match2.Blue3)
|
||||||
|
|
||||||
|
// Shuffle the team positions and check that the subsequent matches in the same round have the same ones.
|
||||||
|
match1.Red1, match1.Red2 = match1.Red2, match1.Red1
|
||||||
|
match2.Blue1, match2.Blue3 = match2.Blue3, match2.Blue1
|
||||||
|
database.SaveMatch(&match1)
|
||||||
|
database.SaveMatch(&match2)
|
||||||
|
scoreMatch(database, "SF1-1", "R")
|
||||||
|
scoreMatch(database, "SF2-1", "B")
|
||||||
|
UpdateEliminationSchedule(database, time.Unix(1000, 0))
|
||||||
|
matches, _ = database.GetMatchesByType("elimination")
|
||||||
|
if assert.Equal(t, 6, len(matches)) {
|
||||||
|
for i := 0; i < 3; i++ {
|
||||||
|
assert.Equal(t, match1.Red1, matches[2*i].Red1)
|
||||||
|
assert.Equal(t, match1.Red2, matches[2*i].Red2)
|
||||||
|
assert.Equal(t, match1.Red3, matches[2*i].Red3)
|
||||||
|
assert.Equal(t, match2.Blue1, matches[2*i+1].Blue1)
|
||||||
|
assert.Equal(t, match2.Blue2, matches[2*i+1].Blue2)
|
||||||
|
assert.Equal(t, match2.Blue3, matches[2*i+1].Blue3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance them to the finals and verify that the team position updates have been propagated.
|
||||||
|
scoreMatch(database, "SF1-2", "R")
|
||||||
|
scoreMatch(database, "SF2-2", "B")
|
||||||
|
UpdateEliminationSchedule(database, time.Unix(5000, 0))
|
||||||
|
matches, _ = database.GetMatchesByType("elimination")
|
||||||
|
if assert.Equal(t, 7, len(matches)) {
|
||||||
|
for i := 4; i < 7; i++ {
|
||||||
|
assert.Equal(t, match1.Red1, matches[i].Red1)
|
||||||
|
assert.Equal(t, match1.Red2, matches[i].Red2)
|
||||||
|
assert.Equal(t, match1.Red3, matches[i].Red3)
|
||||||
|
assert.Equal(t, match2.Blue1, matches[i].Blue1)
|
||||||
|
assert.Equal(t, match2.Blue2, matches[i].Blue2)
|
||||||
|
assert.Equal(t, match2.Blue3, matches[i].Blue3)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func assertMatch(t *testing.T, match model.Match, displayName string, redAlliance int, blueAlliance int) {
|
func assertMatch(t *testing.T, match model.Match, displayName string, redAlliance int, blueAlliance int) {
|
||||||
assert.Equal(t, displayName, match.DisplayName)
|
assert.Equal(t, displayName, match.DisplayName)
|
||||||
assert.Equal(t, redAlliance, match.Red1)
|
assert.Equal(t, redAlliance, match.Red2)
|
||||||
assert.Equal(t, blueAlliance, match.Blue1)
|
assert.Equal(t, blueAlliance, match.Blue2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func scoreMatch(database *model.Database, displayName string, winner string) {
|
func scoreMatch(database *model.Database, displayName string, winner string) {
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import (
|
|||||||
func CreateTestAlliances(database *model.Database, allianceCount int) {
|
func CreateTestAlliances(database *model.Database, allianceCount int) {
|
||||||
for i := 1; i <= allianceCount; i++ {
|
for i := 1; i <= allianceCount; i++ {
|
||||||
database.CreateAllianceTeam(&model.AllianceTeam{0, i, 0, i})
|
database.CreateAllianceTeam(&model.AllianceTeam{0, i, 0, i})
|
||||||
database.CreateAllianceTeam(&model.AllianceTeam{0, i, 1, i})
|
database.CreateAllianceTeam(&model.AllianceTeam{0, i, 1, 10 * i})
|
||||||
database.CreateAllianceTeam(&model.AllianceTeam{0, i, 2, i})
|
database.CreateAllianceTeam(&model.AllianceTeam{0, i, 2, 100 * i})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user