mirror of
https://github.com/Team254/cheesy-arena-lite.git
synced 2026-03-09 21:56:50 -04:00
Update score/ranking models for 2020.
This commit is contained in:
@@ -158,7 +158,8 @@ func (arena *Arena) LoadSettings() error {
|
||||
game.UpdateMatchSounds()
|
||||
arena.MatchTimingNotifier.Notify()
|
||||
|
||||
game.HabDockingThreshold = settings.HabDockingThreshold
|
||||
// TODO(pat): Customize 2020 scoring settings here.
|
||||
//game.HabDockingThreshold = settings.HabDockingThreshold
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -638,8 +639,7 @@ func (arena *Arena) checkCanStartMatch() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if !arena.BypassPreMatchScore && (!arena.RedRealtimeScore.CurrentScore.IsValidPreMatch() ||
|
||||
!arena.BlueRealtimeScore.CurrentScore.IsValidPreMatch()) {
|
||||
if !arena.BypassPreMatchScore {
|
||||
return fmt.Errorf("Cannot start match until pre-match scoring is set")
|
||||
}
|
||||
|
||||
@@ -734,8 +734,7 @@ func (arena *Arena) handlePlcOutput() {
|
||||
// not input, or blinking green if ready.
|
||||
redAllianceReady := arena.checkAllianceStationsReady("R1", "R2", "R3") == nil
|
||||
blueAllianceReady := arena.checkAllianceStationsReady("B1", "B2", "B3") == nil
|
||||
preMatchScoreReady := arena.BypassPreMatchScore || arena.RedRealtimeScore.CurrentScore.IsValidPreMatch() &&
|
||||
arena.BlueRealtimeScore.CurrentScore.IsValidPreMatch()
|
||||
preMatchScoreReady := arena.BypassPreMatchScore
|
||||
greenStackLight := redAllianceReady && blueAllianceReady && preMatchScoreReady &&
|
||||
arena.Plc.GetCycleState(2, 0, 2)
|
||||
arena.Plc.SetStackLights(!redAllianceReady, !blueAllianceReady, !preMatchScoreReady, greenStackLight)
|
||||
@@ -775,7 +774,7 @@ func (arena *Arena) handlePlcOutput() {
|
||||
}
|
||||
arena.Plc.SetCargoShipLights(false)
|
||||
arena.Plc.SetCargoShipMagnets(false)
|
||||
arena.Plc.SetRocketLights(arena.RedScoreSummary().CompleteRocket, arena.BlueScoreSummary().CompleteRocket)
|
||||
arena.Plc.SetRocketLights(false, false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -234,7 +234,6 @@ func getAudienceAllianceScoreFields(allianceScore *RealtimeScore,
|
||||
fields := new(audienceAllianceScoreFields)
|
||||
fields.Score = &allianceScore.CurrentScore
|
||||
fields.ScoreSummary = allianceScoreSummary
|
||||
fields.IsPreMatchScoreReady = allianceScore.CurrentScore.IsValidPreMatch()
|
||||
return fields
|
||||
}
|
||||
|
||||
|
||||
@@ -76,16 +76,6 @@ func TestArenaCheckCanStartMatch(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check scoring constraints.
|
||||
arena.RedRealtimeScore.CurrentScore = *game.TestScoreValidPreMatch()
|
||||
err = arena.checkCanStartMatch()
|
||||
if assert.NotNil(t, err) {
|
||||
assert.Contains(t, err.Error(), "Cannot start match until pre-match scoring is set")
|
||||
}
|
||||
arena.BlueRealtimeScore.CurrentScore = *game.TestScoreValidPreMatch()
|
||||
assert.Nil(t, arena.checkCanStartMatch())
|
||||
arena.RedRealtimeScore.CurrentScore = game.Score{}
|
||||
arena.BlueRealtimeScore.CurrentScore = game.Score{}
|
||||
assert.NotNil(t, arena.checkCanStartMatch())
|
||||
arena.BypassPreMatchScore = true
|
||||
assert.Nil(t, arena.checkCanStartMatch())
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ func (foul *Foul) PointValue() int {
|
||||
return 0
|
||||
}
|
||||
if foul.Rule().IsTechnical {
|
||||
return 10
|
||||
return 15
|
||||
} else {
|
||||
return 3
|
||||
}
|
||||
|
||||
@@ -8,17 +8,16 @@ package game
|
||||
import "math/rand"
|
||||
|
||||
type RankingFields struct {
|
||||
RankingPoints int
|
||||
CargoPoints int
|
||||
HatchPanelPoints int
|
||||
HabClimbPoints int
|
||||
SandstormBonusPoints int
|
||||
Random float64
|
||||
Wins int
|
||||
Losses int
|
||||
Ties int
|
||||
Disqualifications int
|
||||
Played int
|
||||
RankingPoints int
|
||||
AutoPoints int
|
||||
EndgamePoints int
|
||||
TeleopPoints int
|
||||
Random float64
|
||||
Wins int
|
||||
Losses int
|
||||
Ties int
|
||||
Disqualifications int
|
||||
Played int
|
||||
}
|
||||
|
||||
type Ranking struct {
|
||||
@@ -48,18 +47,17 @@ func (fields *RankingFields) AddScoreSummary(ownScore *ScoreSummary, opponentSco
|
||||
} else {
|
||||
fields.Losses += 1
|
||||
}
|
||||
if ownScore.CompleteRocket {
|
||||
if ownScore.ControlPanelRankingPoint {
|
||||
fields.RankingPoints += 1
|
||||
}
|
||||
if ownScore.HabDocking {
|
||||
if ownScore.EndgameRankingPoint {
|
||||
fields.RankingPoints += 1
|
||||
}
|
||||
|
||||
// Assign tiebreaker points.
|
||||
fields.CargoPoints += ownScore.CargoPoints
|
||||
fields.HatchPanelPoints += ownScore.HatchPanelPoints
|
||||
fields.HabClimbPoints += ownScore.HabClimbPoints
|
||||
fields.SandstormBonusPoints += ownScore.SandstormBonusPoints
|
||||
fields.AutoPoints += ownScore.AutoPoints
|
||||
fields.EndgamePoints += ownScore.EndgamePoints
|
||||
fields.TeleopPoints += ownScore.TeleopPowerCellPoints + ownScore.ControlPanelPoints
|
||||
|
||||
// Store a random value to be used as the last tiebreaker if necessary.
|
||||
fields.Random = rand.Float64()
|
||||
@@ -77,19 +75,16 @@ func (rankings Rankings) Less(i, j int) bool {
|
||||
|
||||
// Use cross-multiplication to keep it in integer math.
|
||||
if a.RankingPoints*b.Played == b.RankingPoints*a.Played {
|
||||
if a.CargoPoints*b.Played == b.CargoPoints*a.Played {
|
||||
if a.HatchPanelPoints*b.Played == b.HatchPanelPoints*a.Played {
|
||||
if a.HabClimbPoints*b.Played == b.HabClimbPoints*a.Played {
|
||||
if a.SandstormBonusPoints*b.Played == b.SandstormBonusPoints*a.Played {
|
||||
return a.Random > b.Random
|
||||
}
|
||||
return a.SandstormBonusPoints*b.Played > b.SandstormBonusPoints*a.Played
|
||||
if a.AutoPoints*b.Played == b.AutoPoints*a.Played {
|
||||
if a.EndgamePoints*b.Played == b.EndgamePoints*a.Played {
|
||||
if a.TeleopPoints*b.Played == b.TeleopPoints*a.Played {
|
||||
return a.Random > b.Random
|
||||
}
|
||||
return a.HabClimbPoints*b.Played > b.HabClimbPoints*a.Played
|
||||
return a.TeleopPoints*b.Played > b.TeleopPoints*a.Played
|
||||
}
|
||||
return a.HatchPanelPoints*b.Played > b.HatchPanelPoints*a.Played
|
||||
return a.EndgamePoints*b.Played > b.EndgamePoints*a.Played
|
||||
}
|
||||
return a.CargoPoints*b.Played > b.CargoPoints*a.Played
|
||||
return a.AutoPoints*b.Played > b.AutoPoints*a.Played
|
||||
}
|
||||
return a.RankingPoints*b.Played > b.RankingPoints*a.Played
|
||||
}
|
||||
|
||||
@@ -20,55 +20,51 @@ func TestAddScoreSummary(t *testing.T) {
|
||||
|
||||
// Add a loss.
|
||||
rankingFields.AddScoreSummary(redSummary, blueSummary, false)
|
||||
assert.Equal(t, RankingFields{1, 30, 20, 12, 9, 0.9451961492941164, 0, 1, 0, 0, 1}, rankingFields)
|
||||
assert.Equal(t, RankingFields{1, 94, 75, 48, 0.9451961492941164, 0, 1, 0, 0, 1}, rankingFields)
|
||||
|
||||
// Add a win.
|
||||
rankingFields.AddScoreSummary(blueSummary, redSummary, false)
|
||||
assert.Equal(t, RankingFields{4, 48, 24, 33, 15, 0.24496508529377975, 1, 1, 0, 0, 2}, rankingFields)
|
||||
assert.Equal(t, RankingFields{4, 111, 125, 200, 0.24496508529377975, 1, 1, 0, 0, 2}, rankingFields)
|
||||
|
||||
// Add a tie.
|
||||
rankingFields.AddScoreSummary(redSummary, redSummary, false)
|
||||
assert.Equal(t, RankingFields{6, 78, 44, 45, 24, 0.6559562651954052, 1, 1, 1, 0, 3}, rankingFields)
|
||||
assert.Equal(t, RankingFields{6, 205, 200, 248, 0.6559562651954052, 1, 1, 1, 0, 3}, rankingFields)
|
||||
|
||||
// Add a disqualification.
|
||||
rankingFields.AddScoreSummary(blueSummary, redSummary, true)
|
||||
assert.Equal(t, RankingFields{6, 78, 44, 45, 24, 0.6559562651954052, 1, 1, 1, 1, 4}, rankingFields)
|
||||
assert.Equal(t, RankingFields{6, 205, 200, 248, 0.6559562651954052, 1, 1, 1, 1, 4}, rankingFields)
|
||||
}
|
||||
|
||||
func TestSortRankings(t *testing.T) {
|
||||
// Check tiebreakers.
|
||||
rankings := make(Rankings, 12)
|
||||
rankings[0] = &Ranking{1, 0, RankingFields{50, 50, 50, 50, 50, 0.49, 3, 2, 1, 0, 10}}
|
||||
rankings[1] = &Ranking{2, 0, RankingFields{50, 50, 50, 50, 50, 0.51, 3, 2, 1, 0, 10}}
|
||||
rankings[2] = &Ranking{3, 0, RankingFields{50, 50, 50, 50, 49, 0.50, 3, 2, 1, 0, 10}}
|
||||
rankings[3] = &Ranking{4, 0, RankingFields{50, 50, 50, 50, 51, 0.50, 3, 2, 1, 0, 10}}
|
||||
rankings[4] = &Ranking{5, 0, RankingFields{50, 50, 50, 49, 50, 0.50, 3, 2, 1, 0, 10}}
|
||||
rankings[5] = &Ranking{6, 0, RankingFields{50, 50, 50, 51, 50, 0.50, 3, 2, 1, 0, 10}}
|
||||
rankings[6] = &Ranking{7, 0, RankingFields{50, 50, 49, 50, 50, 0.50, 3, 2, 1, 0, 10}}
|
||||
rankings[7] = &Ranking{8, 0, RankingFields{50, 50, 51, 50, 50, 0.50, 3, 2, 1, 0, 10}}
|
||||
rankings[8] = &Ranking{9, 0, RankingFields{50, 49, 50, 50, 50, 0.50, 3, 2, 1, 0, 10}}
|
||||
rankings[9] = &Ranking{10, 0, RankingFields{50, 51, 50, 50, 50, 0.50, 3, 2, 1, 0, 10}}
|
||||
rankings[10] = &Ranking{11, 0, RankingFields{49, 50, 50, 50, 50, 0.50, 3, 2, 1, 0, 10}}
|
||||
rankings[11] = &Ranking{12, 0, RankingFields{51, 50, 50, 50, 50, 0.50, 3, 2, 1, 0, 10}}
|
||||
rankings := make(Rankings, 10)
|
||||
rankings[0] = &Ranking{1, 0, RankingFields{50, 50, 50, 50, 0.49, 3, 2, 1, 0, 10}}
|
||||
rankings[1] = &Ranking{2, 0, RankingFields{50, 50, 50, 50, 0.51, 3, 2, 1, 0, 10}}
|
||||
rankings[2] = &Ranking{3, 0, RankingFields{50, 50, 50, 49, 0.50, 3, 2, 1, 0, 10}}
|
||||
rankings[3] = &Ranking{4, 0, RankingFields{50, 50, 50, 51, 0.50, 3, 2, 1, 0, 10}}
|
||||
rankings[4] = &Ranking{5, 0, RankingFields{50, 50, 49, 50, 0.50, 3, 2, 1, 0, 10}}
|
||||
rankings[5] = &Ranking{6, 0, RankingFields{50, 50, 51, 50, 0.50, 3, 2, 1, 0, 10}}
|
||||
rankings[6] = &Ranking{7, 0, RankingFields{50, 49, 50, 50, 0.50, 3, 2, 1, 0, 10}}
|
||||
rankings[7] = &Ranking{8, 0, RankingFields{50, 51, 50, 50, 0.50, 3, 2, 1, 0, 10}}
|
||||
rankings[8] = &Ranking{9, 0, RankingFields{49, 50, 50, 50, 0.50, 3, 2, 1, 0, 10}}
|
||||
rankings[9] = &Ranking{10, 0, RankingFields{51, 50, 50, 50, 0.50, 3, 2, 1, 0, 10}}
|
||||
sort.Sort(rankings)
|
||||
assert.Equal(t, 12, rankings[0].TeamId)
|
||||
assert.Equal(t, 10, rankings[1].TeamId)
|
||||
assert.Equal(t, 8, rankings[2].TeamId)
|
||||
assert.Equal(t, 6, rankings[3].TeamId)
|
||||
assert.Equal(t, 4, rankings[4].TeamId)
|
||||
assert.Equal(t, 2, rankings[5].TeamId)
|
||||
assert.Equal(t, 1, rankings[6].TeamId)
|
||||
assert.Equal(t, 3, rankings[7].TeamId)
|
||||
assert.Equal(t, 5, rankings[8].TeamId)
|
||||
assert.Equal(t, 7, rankings[9].TeamId)
|
||||
assert.Equal(t, 9, rankings[10].TeamId)
|
||||
assert.Equal(t, 11, rankings[11].TeamId)
|
||||
assert.Equal(t, 10, rankings[0].TeamId)
|
||||
assert.Equal(t, 8, rankings[1].TeamId)
|
||||
assert.Equal(t, 6, rankings[2].TeamId)
|
||||
assert.Equal(t, 4, rankings[3].TeamId)
|
||||
assert.Equal(t, 2, rankings[4].TeamId)
|
||||
assert.Equal(t, 1, rankings[5].TeamId)
|
||||
assert.Equal(t, 3, rankings[6].TeamId)
|
||||
assert.Equal(t, 5, rankings[7].TeamId)
|
||||
assert.Equal(t, 7, rankings[8].TeamId)
|
||||
assert.Equal(t, 9, rankings[9].TeamId)
|
||||
|
||||
// Check with unequal number of matches played.
|
||||
rankings = make(Rankings, 3)
|
||||
rankings[0] = &Ranking{1, 0, RankingFields{10, 25, 25, 25, 25, 0.49, 3, 2, 1, 0, 5}}
|
||||
rankings[1] = &Ranking{2, 0, RankingFields{19, 50, 50, 50, 50, 0.51, 3, 2, 1, 0, 9}}
|
||||
rankings[2] = &Ranking{3, 0, RankingFields{20, 50, 50, 50, 50, 0.51, 3, 2, 1, 0, 10}}
|
||||
rankings[0] = &Ranking{1, 0, RankingFields{10, 25, 25, 25, 0.49, 3, 2, 1, 0, 5}}
|
||||
rankings[1] = &Ranking{2, 0, RankingFields{19, 50, 50, 50, 0.51, 3, 2, 1, 0, 9}}
|
||||
rankings[2] = &Ranking{3, 0, RankingFields{20, 50, 50, 50, 0.51, 3, 2, 1, 0, 10}}
|
||||
sort.Sort(rankings)
|
||||
assert.Equal(t, 2, rankings[0].TeamId)
|
||||
assert.Equal(t, 3, rankings[1].TeamId)
|
||||
|
||||
265
game/score.go
265
game/score.go
@@ -1,4 +1,4 @@
|
||||
// Copyright 2017 Team 254. All Rights Reserved.
|
||||
// Copyright 2020 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
//
|
||||
// Model representing the instantaneous score of a match.
|
||||
@@ -6,41 +6,62 @@
|
||||
package game
|
||||
|
||||
type Score struct {
|
||||
RobotStartLevels [3]int
|
||||
SandstormBonuses [3]bool
|
||||
CargoBaysPreMatch [8]BayStatus
|
||||
CargoBays [8]BayStatus
|
||||
RocketNearLeftBays [3]BayStatus
|
||||
RocketNearRightBays [3]BayStatus
|
||||
RocketFarLeftBays [3]BayStatus
|
||||
RocketFarRightBays [3]BayStatus
|
||||
RobotEndLevels [3]int
|
||||
Fouls []Foul
|
||||
ElimDq bool
|
||||
ExitedInitiationLine [3]bool
|
||||
AutoCellsBottom [2]int
|
||||
AutoCellsOuter [2]int
|
||||
AutoCellsInner [2]int
|
||||
TeleopPeriodStarted bool
|
||||
TeleopCellsBottom [4]int
|
||||
TeleopCellsOuter [4]int
|
||||
TeleopCellsInner [4]int
|
||||
RotationControl bool
|
||||
PositionControl bool
|
||||
EndgameStatuses [3]EndgameStatus
|
||||
RungIsLevel bool
|
||||
Fouls []Foul
|
||||
ElimDq bool
|
||||
}
|
||||
|
||||
type ScoreSummary struct {
|
||||
CargoPoints int
|
||||
HatchPanelPoints int
|
||||
HabClimbPoints int
|
||||
SandstormBonusPoints int
|
||||
FoulPoints int
|
||||
Score int
|
||||
CompleteRocket bool
|
||||
HabDocking bool
|
||||
InitiationLinePoints int
|
||||
AutoPowerCellPoints int
|
||||
AutoPoints int
|
||||
TeleopPowerCellPoints int
|
||||
ControlPanelPoints int
|
||||
EndgamePoints int
|
||||
FoulPoints int
|
||||
Score int
|
||||
StagesAtCapacity [3]bool
|
||||
StagesActivated [3]bool
|
||||
ControlPanelRankingPoint bool
|
||||
EndgameRankingPoint bool
|
||||
}
|
||||
|
||||
// Represents the state of a cargo ship or rocket bay.
|
||||
type BayStatus int
|
||||
// Defines the number of power cells that must be scored within each Stage before it can be activated.
|
||||
var StageCapacities = map[Stage]int{
|
||||
Stage1: 9,
|
||||
Stage2: 20,
|
||||
Stage3: 20,
|
||||
}
|
||||
|
||||
// Represents a Stage towards whose capacity scored power cells are counted.
|
||||
type Stage int
|
||||
|
||||
const (
|
||||
BayEmpty BayStatus = iota
|
||||
BayHatch
|
||||
BayHatchCargo
|
||||
BayCargo
|
||||
Stage1 Stage = iota
|
||||
Stage2
|
||||
Stage3
|
||||
StageExtra
|
||||
)
|
||||
|
||||
var HabDockingThreshold = 15
|
||||
// Represents the state of a robot at the end of the match.
|
||||
type EndgameStatus int
|
||||
|
||||
const (
|
||||
None EndgameStatus = iota
|
||||
Park
|
||||
Hang
|
||||
)
|
||||
|
||||
// Calculates and returns the summary fields used for ranking and display.
|
||||
func (score *Score) Summarize(opponentFouls []Foul) *ScoreSummary {
|
||||
@@ -51,85 +72,77 @@ func (score *Score) Summarize(opponentFouls []Foul) *ScoreSummary {
|
||||
return summary
|
||||
}
|
||||
|
||||
// Calculate sandstorm bonus points.
|
||||
for i, robotStartLevel := range score.RobotStartLevels {
|
||||
if score.SandstormBonuses[i] {
|
||||
if robotStartLevel == 1 {
|
||||
summary.SandstormBonusPoints += 3
|
||||
} else if robotStartLevel == 2 {
|
||||
summary.SandstormBonusPoints += 6
|
||||
}
|
||||
// Calculate autonomous period points.
|
||||
for _, exited := range score.ExitedInitiationLine {
|
||||
if exited {
|
||||
summary.InitiationLinePoints += 5
|
||||
}
|
||||
}
|
||||
for i := 0; i < len(score.AutoCellsBottom); i++ {
|
||||
summary.AutoPowerCellPoints += 2 * score.AutoCellsBottom[i]
|
||||
summary.AutoPowerCellPoints += 4 * score.AutoCellsOuter[i]
|
||||
summary.AutoPowerCellPoints += 6 * score.AutoCellsInner[i]
|
||||
}
|
||||
summary.AutoPoints = summary.InitiationLinePoints + summary.AutoPowerCellPoints
|
||||
|
||||
// Calculate teleoperated period power cell points.
|
||||
for i := 0; i < len(score.TeleopCellsBottom); i++ {
|
||||
summary.TeleopPowerCellPoints += score.TeleopCellsBottom[i]
|
||||
summary.TeleopPowerCellPoints += 2 * score.TeleopCellsOuter[i]
|
||||
summary.TeleopPowerCellPoints += 3 * score.TeleopCellsInner[i]
|
||||
}
|
||||
|
||||
// Calculate cargo and hatch panel points.
|
||||
for i, bayStatus := range score.CargoBays {
|
||||
if bayStatus == BayHatchCargo {
|
||||
summary.CargoPoints += 3
|
||||
if score.CargoBaysPreMatch[i] != BayHatch {
|
||||
summary.HatchPanelPoints += 2
|
||||
}
|
||||
} else if bayStatus == BayHatch && score.CargoBaysPreMatch[i] != BayHatch {
|
||||
summary.HatchPanelPoints += 2
|
||||
}
|
||||
// Calculate control panel points and stages.
|
||||
for i := Stage1; i <= Stage3; i++ {
|
||||
summary.StagesAtCapacity[i] = score.StageAtCapacity(i)
|
||||
summary.StagesActivated[i] = score.StageActivated(i)
|
||||
}
|
||||
summary.addRocketHalfPoints(score.RocketNearLeftBays)
|
||||
summary.addRocketHalfPoints(score.RocketNearRightBays)
|
||||
summary.addRocketHalfPoints(score.RocketFarLeftBays)
|
||||
summary.addRocketHalfPoints(score.RocketFarRightBays)
|
||||
|
||||
// Calculate hab climb points.
|
||||
for _, level := range score.RobotEndLevels {
|
||||
switch level {
|
||||
case 1:
|
||||
summary.HabClimbPoints += 3
|
||||
case 2:
|
||||
summary.HabClimbPoints += 6
|
||||
case 3:
|
||||
summary.HabClimbPoints += 12
|
||||
}
|
||||
if summary.StagesActivated[Stage2] {
|
||||
summary.ControlPanelPoints += 10
|
||||
}
|
||||
if summary.StagesActivated[Stage3] {
|
||||
summary.ControlPanelPoints += 20
|
||||
summary.ControlPanelRankingPoint = true
|
||||
}
|
||||
|
||||
// Calculate bonus ranking points.
|
||||
if score.isLevelComplete(0) && score.isLevelComplete(1) && score.isLevelComplete(2) {
|
||||
summary.CompleteRocket = true
|
||||
} else {
|
||||
// Check for the opponent fouls that automatically trigger the ranking point.
|
||||
for _, foul := range opponentFouls {
|
||||
if foul.Rule() == nil {
|
||||
continue
|
||||
}
|
||||
if foul.Rule().IsRankingPoint {
|
||||
summary.CompleteRocket = true
|
||||
break
|
||||
}
|
||||
// Calculate endgame points.
|
||||
for _, status := range score.EndgameStatuses {
|
||||
if status == Park {
|
||||
summary.EndgamePoints += 5
|
||||
} else if status == Hang {
|
||||
summary.EndgamePoints += 25
|
||||
}
|
||||
}
|
||||
if summary.HabClimbPoints >= HabDockingThreshold {
|
||||
summary.HabDocking = true
|
||||
if summary.EndgamePoints > 0 && score.RungIsLevel {
|
||||
summary.EndgamePoints += 15
|
||||
}
|
||||
summary.EndgameRankingPoint = summary.EndgamePoints >= 65
|
||||
|
||||
// Calculate penalty points.
|
||||
for _, foul := range opponentFouls {
|
||||
summary.FoulPoints += foul.PointValue()
|
||||
}
|
||||
|
||||
summary.Score = summary.CargoPoints + summary.HatchPanelPoints + summary.HabClimbPoints +
|
||||
summary.SandstormBonusPoints + summary.FoulPoints
|
||||
summary.Score = summary.AutoPoints + summary.TeleopPowerCellPoints + summary.ControlPanelPoints +
|
||||
summary.EndgamePoints + summary.FoulPoints
|
||||
|
||||
return summary
|
||||
}
|
||||
|
||||
// Returns true if and only if all fields of the two scores are equal.
|
||||
func (score *Score) Equals(other *Score) bool {
|
||||
if score.RobotStartLevels != other.RobotStartLevels ||
|
||||
score.SandstormBonuses != other.SandstormBonuses ||
|
||||
score.CargoBaysPreMatch != other.CargoBaysPreMatch ||
|
||||
score.CargoBays != other.CargoBays ||
|
||||
score.RocketNearLeftBays != other.RocketNearLeftBays ||
|
||||
score.RocketNearRightBays != other.RocketNearRightBays ||
|
||||
score.RocketFarLeftBays != other.RocketFarLeftBays ||
|
||||
score.RocketFarRightBays != other.RocketFarRightBays ||
|
||||
score.RobotEndLevels != other.RobotEndLevels ||
|
||||
if score.ExitedInitiationLine != other.ExitedInitiationLine ||
|
||||
score.AutoCellsBottom != other.AutoCellsBottom ||
|
||||
score.AutoCellsOuter != other.AutoCellsOuter ||
|
||||
score.AutoCellsInner != other.AutoCellsInner ||
|
||||
score.TeleopPeriodStarted != other.TeleopPeriodStarted ||
|
||||
score.TeleopCellsBottom != other.TeleopCellsBottom ||
|
||||
score.TeleopCellsOuter != other.TeleopCellsOuter ||
|
||||
score.TeleopCellsInner != other.TeleopCellsInner ||
|
||||
score.RotationControl != other.RotationControl ||
|
||||
score.PositionControl != other.PositionControl ||
|
||||
score.EndgameStatuses != other.EndgameStatuses ||
|
||||
score.RungIsLevel != other.RungIsLevel ||
|
||||
score.ElimDq != other.ElimDq ||
|
||||
len(score.Fouls) != len(other.Fouls) {
|
||||
return false
|
||||
@@ -144,51 +157,51 @@ func (score *Score) Equals(other *Score) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Returns true if the score represents a valid pre-match state.
|
||||
func (score *Score) IsValidPreMatch() bool {
|
||||
for i := 0; i < 3; i++ {
|
||||
// Ensure robot start level is set.
|
||||
if score.RobotStartLevels[i] == 0 || score.RobotStartLevels[i] > 3 {
|
||||
return false
|
||||
}
|
||||
|
||||
// Ensure other robot fields and rocket bays are empty.
|
||||
if score.SandstormBonuses[i] || score.RobotEndLevels[i] != 0 || score.RocketNearLeftBays[i] != BayEmpty ||
|
||||
score.RocketNearRightBays[i] != BayEmpty || score.RocketFarLeftBays[i] != BayEmpty ||
|
||||
score.RocketFarRightBays[i] != BayEmpty {
|
||||
return false
|
||||
}
|
||||
// Returns the Stage (1-3) that the score represents, in terms of which Stage scored power cells should count towards.
|
||||
func (score *Score) CellCountingStage() Stage {
|
||||
if score.StageActivated(Stage3) {
|
||||
return StageExtra
|
||||
}
|
||||
for i := 0; i < 8; i++ {
|
||||
if i == 3 || i == 4 {
|
||||
// Ensure cargo ship front bays are empty.
|
||||
if score.CargoBaysPreMatch[i] != BayEmpty {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
// Ensure cargo ship side bays have either a hatch or cargo but not both.
|
||||
if !(score.CargoBaysPreMatch[i] == BayHatch || score.CargoBaysPreMatch[i] == BayCargo) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if score.StageActivated(Stage2) {
|
||||
return Stage3
|
||||
}
|
||||
return score.CargoBays == score.CargoBaysPreMatch
|
||||
if score.StageActivated(Stage1) {
|
||||
return Stage2
|
||||
}
|
||||
return Stage1
|
||||
}
|
||||
|
||||
// Calculates the cargo and hatch panel points for the given rocket half and adds them to the summary.
|
||||
func (summary *ScoreSummary) addRocketHalfPoints(rocketHalf [3]BayStatus) {
|
||||
for _, bayStatus := range rocketHalf {
|
||||
if bayStatus == BayHatchCargo {
|
||||
summary.CargoPoints += 3
|
||||
summary.HatchPanelPoints += 2
|
||||
} else if bayStatus == BayHatch {
|
||||
summary.HatchPanelPoints += 2
|
||||
}
|
||||
// Returns true if the preconditions are satisfied for the given Stage to be activated.
|
||||
func (score *Score) StageAtCapacity(stage Stage) bool {
|
||||
if stage > Stage1 && !score.StageActivated(stage-1) {
|
||||
return false
|
||||
}
|
||||
if capacity, ok := StageCapacities[stage]; ok && score.stagePowerCells(stage) >= capacity {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Returns true if the level is complete for at least one rocket.
|
||||
func (score *Score) isLevelComplete(level int) bool {
|
||||
return score.RocketNearLeftBays[level] == BayHatchCargo && score.RocketNearRightBays[level] == BayHatchCargo ||
|
||||
score.RocketFarLeftBays[level] == BayHatchCargo && score.RocketFarRightBays[level] == BayHatchCargo
|
||||
// Returns true if the given Stage has been activated.
|
||||
func (score *Score) StageActivated(stage Stage) bool {
|
||||
if score.StageAtCapacity(stage) {
|
||||
switch stage {
|
||||
case Stage1:
|
||||
return score.TeleopPeriodStarted
|
||||
case Stage2:
|
||||
return score.RotationControl
|
||||
case Stage3:
|
||||
return score.PositionControl
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Returns the total count of scored power cells within the given Stage.
|
||||
func (score *Score) stagePowerCells(stage Stage) int {
|
||||
cells := score.TeleopCellsBottom[stage] + score.TeleopCellsOuter[stage] + score.TeleopCellsInner[stage]
|
||||
if stage < Stage3 {
|
||||
cells += score.AutoCellsBottom[stage] + score.AutoCellsOuter[stage] + score.AutoCellsInner[stage]
|
||||
}
|
||||
return cells
|
||||
}
|
||||
|
||||
@@ -13,47 +13,36 @@ func TestScoreSummary(t *testing.T) {
|
||||
blueScore := TestScore2()
|
||||
|
||||
redSummary := redScore.Summarize(blueScore.Fouls)
|
||||
assert.Equal(t, 30, redSummary.CargoPoints)
|
||||
assert.Equal(t, 20, redSummary.HatchPanelPoints)
|
||||
assert.Equal(t, 12, redSummary.HabClimbPoints)
|
||||
assert.Equal(t, 9, redSummary.SandstormBonusPoints)
|
||||
assert.Equal(t, 10, redSummary.InitiationLinePoints)
|
||||
assert.Equal(t, 84, redSummary.AutoPowerCellPoints)
|
||||
assert.Equal(t, 94, redSummary.AutoPoints)
|
||||
assert.Equal(t, 38, redSummary.TeleopPowerCellPoints)
|
||||
assert.Equal(t, 10, redSummary.ControlPanelPoints)
|
||||
assert.Equal(t, 75, redSummary.EndgamePoints)
|
||||
assert.Equal(t, 0, redSummary.FoulPoints)
|
||||
assert.Equal(t, 71, redSummary.Score)
|
||||
assert.Equal(t, true, redSummary.CompleteRocket)
|
||||
assert.Equal(t, false, redSummary.HabDocking)
|
||||
assert.Equal(t, 217, redSummary.Score)
|
||||
assert.Equal(t, [3]bool{true, true, false}, redSummary.StagesAtCapacity)
|
||||
assert.Equal(t, [3]bool{true, true, false}, redSummary.StagesActivated)
|
||||
assert.Equal(t, false, redSummary.ControlPanelRankingPoint)
|
||||
assert.Equal(t, true, redSummary.EndgameRankingPoint)
|
||||
|
||||
blueSummary := blueScore.Summarize(redScore.Fouls)
|
||||
assert.Equal(t, 18, blueSummary.CargoPoints)
|
||||
assert.Equal(t, 4, blueSummary.HatchPanelPoints)
|
||||
assert.Equal(t, 21, blueSummary.HabClimbPoints)
|
||||
assert.Equal(t, 6, blueSummary.SandstormBonusPoints)
|
||||
assert.Equal(t, 23, blueSummary.FoulPoints)
|
||||
assert.Equal(t, 72, blueSummary.Score)
|
||||
assert.Equal(t, false, blueSummary.CompleteRocket)
|
||||
assert.Equal(t, true, blueSummary.HabDocking)
|
||||
assert.Equal(t, 5, blueSummary.InitiationLinePoints)
|
||||
assert.Equal(t, 12, blueSummary.AutoPowerCellPoints)
|
||||
assert.Equal(t, 17, blueSummary.AutoPoints)
|
||||
assert.Equal(t, 122, blueSummary.TeleopPowerCellPoints)
|
||||
assert.Equal(t, 30, blueSummary.ControlPanelPoints)
|
||||
assert.Equal(t, 50, blueSummary.EndgamePoints)
|
||||
assert.Equal(t, 33, blueSummary.FoulPoints)
|
||||
assert.Equal(t, 252, blueSummary.Score)
|
||||
assert.Equal(t, [3]bool{true, true, true}, blueSummary.StagesAtCapacity)
|
||||
assert.Equal(t, [3]bool{true, true, true}, blueSummary.StagesActivated)
|
||||
assert.Equal(t, true, blueSummary.ControlPanelRankingPoint)
|
||||
assert.Equal(t, false, blueSummary.EndgameRankingPoint)
|
||||
|
||||
// Test invalid foul.
|
||||
redScore.Fouls[0].RuleId = 0
|
||||
assert.Equal(t, 13, blueScore.Summarize(redScore.Fouls).FoulPoints)
|
||||
|
||||
// Test rocket completion boundary conditions.
|
||||
assert.Equal(t, true, redScore.Summarize(blueScore.Fouls).CompleteRocket)
|
||||
redScore.RocketFarLeftBays[1] = BayHatch
|
||||
assert.Equal(t, false, redScore.Summarize(blueScore.Fouls).CompleteRocket)
|
||||
redScore.RocketNearLeftBays[1] = BayHatchCargo
|
||||
redScore.RocketNearRightBays[1] = BayHatchCargo
|
||||
assert.Equal(t, true, redScore.Summarize(blueScore.Fouls).CompleteRocket)
|
||||
redScore.RocketNearLeftBays[2] = BayHatch
|
||||
assert.Equal(t, false, redScore.Summarize(blueScore.Fouls).CompleteRocket)
|
||||
redScore.Fouls[2].RuleId = 15
|
||||
assert.Equal(t, true, redScore.Summarize(redScore.Fouls).CompleteRocket)
|
||||
|
||||
// Test hab docking boundary conditions.
|
||||
assert.Equal(t, true, blueScore.Summarize(redScore.Fouls).HabDocking)
|
||||
HabDockingThreshold = 24
|
||||
assert.Equal(t, false, blueScore.Summarize(redScore.Fouls).HabDocking)
|
||||
blueScore.RobotEndLevels[0] = 3
|
||||
assert.Equal(t, true, blueScore.Summarize(redScore.Fouls).HabDocking)
|
||||
assert.Equal(t, 18, blueScore.Summarize(redScore.Fouls).FoulPoints)
|
||||
|
||||
// Test elimination disqualification.
|
||||
redScore.ElimDq = true
|
||||
@@ -63,6 +52,80 @@ func TestScoreSummary(t *testing.T) {
|
||||
assert.Equal(t, 0, blueScore.Summarize(redScore.Fouls).Score)
|
||||
}
|
||||
|
||||
func TestScoreSummaryBoundaryConditions(t *testing.T) {
|
||||
// Test control panel boundary conditions.
|
||||
score := TestScore2()
|
||||
summary := score.Summarize(score.Fouls)
|
||||
assert.Equal(t, StageExtra, score.CellCountingStage())
|
||||
assert.Equal(t, [3]bool{true, true, true}, summary.StagesAtCapacity)
|
||||
assert.Equal(t, [3]bool{true, true, true}, summary.StagesActivated)
|
||||
assert.Equal(t, true, summary.ControlPanelRankingPoint)
|
||||
assert.Equal(t, 219, summary.Score)
|
||||
|
||||
score.TeleopCellsInner[0]--
|
||||
summary = score.Summarize(score.Fouls)
|
||||
assert.Equal(t, Stage1, score.CellCountingStage())
|
||||
assert.Equal(t, [3]bool{false, false, false}, summary.StagesAtCapacity)
|
||||
assert.Equal(t, [3]bool{false, false, false}, summary.StagesActivated)
|
||||
assert.Equal(t, false, summary.ControlPanelRankingPoint)
|
||||
assert.Equal(t, 186, summary.Score)
|
||||
score.TeleopCellsInner[0]++
|
||||
|
||||
score.TeleopPeriodStarted = false
|
||||
summary = score.Summarize(score.Fouls)
|
||||
assert.Equal(t, Stage1, score.CellCountingStage())
|
||||
assert.Equal(t, [3]bool{true, false, false}, summary.StagesAtCapacity)
|
||||
assert.Equal(t, [3]bool{false, false, false}, summary.StagesActivated)
|
||||
assert.Equal(t, false, summary.ControlPanelRankingPoint)
|
||||
assert.Equal(t, 189, summary.Score)
|
||||
score.TeleopPeriodStarted = true
|
||||
|
||||
score.TeleopCellsOuter[1]--
|
||||
summary = score.Summarize(score.Fouls)
|
||||
assert.Equal(t, Stage2, score.CellCountingStage())
|
||||
assert.Equal(t, [3]bool{true, false, false}, summary.StagesAtCapacity)
|
||||
assert.Equal(t, [3]bool{true, false, false}, summary.StagesActivated)
|
||||
assert.Equal(t, false, summary.ControlPanelRankingPoint)
|
||||
assert.Equal(t, 187, summary.Score)
|
||||
score.TeleopCellsOuter[1]++
|
||||
|
||||
score.RotationControl = false
|
||||
summary = score.Summarize(score.Fouls)
|
||||
assert.Equal(t, Stage2, score.CellCountingStage())
|
||||
assert.Equal(t, [3]bool{true, true, false}, summary.StagesAtCapacity)
|
||||
assert.Equal(t, [3]bool{true, false, false}, summary.StagesActivated)
|
||||
assert.Equal(t, false, summary.ControlPanelRankingPoint)
|
||||
assert.Equal(t, 189, summary.Score)
|
||||
score.RotationControl = true
|
||||
|
||||
score.TeleopCellsInner[2] -= 3
|
||||
summary = score.Summarize(score.Fouls)
|
||||
assert.Equal(t, Stage3, score.CellCountingStage())
|
||||
assert.Equal(t, [3]bool{true, true, false}, summary.StagesAtCapacity)
|
||||
assert.Equal(t, [3]bool{true, true, false}, summary.StagesActivated)
|
||||
assert.Equal(t, false, summary.ControlPanelRankingPoint)
|
||||
assert.Equal(t, 190, summary.Score)
|
||||
score.TeleopCellsInner[2] += 3
|
||||
|
||||
score.PositionControl = false
|
||||
summary = score.Summarize(score.Fouls)
|
||||
assert.Equal(t, Stage3, score.CellCountingStage())
|
||||
assert.Equal(t, [3]bool{true, true, true}, summary.StagesAtCapacity)
|
||||
assert.Equal(t, [3]bool{true, true, false}, summary.StagesActivated)
|
||||
assert.Equal(t, false, summary.ControlPanelRankingPoint)
|
||||
assert.Equal(t, 199, summary.Score)
|
||||
|
||||
// Test endgame boundary conditions.
|
||||
score = TestScore1()
|
||||
assert.Equal(t, true, score.Summarize(score.Fouls).EndgameRankingPoint)
|
||||
score.EndgameStatuses[0] = None
|
||||
assert.Equal(t, false, score.Summarize(score.Fouls).EndgameRankingPoint)
|
||||
score.RungIsLevel = true
|
||||
assert.Equal(t, true, score.Summarize(score.Fouls).EndgameRankingPoint)
|
||||
score.EndgameStatuses[2] = Park
|
||||
assert.Equal(t, false, score.Summarize(score.Fouls).EndgameRankingPoint)
|
||||
}
|
||||
|
||||
func TestScoreEquals(t *testing.T) {
|
||||
score1 := TestScore1()
|
||||
score2 := TestScore1()
|
||||
@@ -73,47 +136,63 @@ func TestScoreEquals(t *testing.T) {
|
||||
assert.False(t, score1.Equals(score3))
|
||||
assert.False(t, score3.Equals(score1))
|
||||
|
||||
score2.RobotStartLevels[2] = 3
|
||||
score2 = TestScore1()
|
||||
score2.ExitedInitiationLine[0] = false
|
||||
assert.False(t, score1.Equals(score2))
|
||||
assert.False(t, score2.Equals(score1))
|
||||
|
||||
score2 = TestScore1()
|
||||
score2.SandstormBonuses[0] = false
|
||||
score2.AutoCellsBottom[1] = 3
|
||||
assert.False(t, score1.Equals(score2))
|
||||
assert.False(t, score2.Equals(score1))
|
||||
|
||||
score2 = TestScore1()
|
||||
score2.CargoBaysPreMatch[7] = BayCargo
|
||||
score2.AutoCellsOuter[0] = 7
|
||||
assert.False(t, score1.Equals(score2))
|
||||
assert.False(t, score2.Equals(score1))
|
||||
|
||||
score2 = TestScore1()
|
||||
score2.CargoBays[5] = BayHatchCargo
|
||||
score2.AutoCellsInner[1] = 8
|
||||
assert.False(t, score1.Equals(score2))
|
||||
assert.False(t, score2.Equals(score1))
|
||||
|
||||
score2 = TestScore1()
|
||||
score2.RocketNearLeftBays[0] = BayEmpty
|
||||
score2.TeleopPeriodStarted = !score2.TeleopPeriodStarted
|
||||
assert.False(t, score1.Equals(score2))
|
||||
assert.False(t, score2.Equals(score1))
|
||||
|
||||
score2 = TestScore1()
|
||||
score2.RocketNearRightBays[1] = BayHatchCargo
|
||||
score2.TeleopCellsBottom[2] = 30
|
||||
assert.False(t, score1.Equals(score2))
|
||||
assert.False(t, score2.Equals(score1))
|
||||
|
||||
score2 = TestScore1()
|
||||
score2.RocketFarLeftBays[2] = BayCargo
|
||||
score2.TeleopCellsOuter[1] = 31
|
||||
assert.False(t, score1.Equals(score2))
|
||||
assert.False(t, score2.Equals(score1))
|
||||
|
||||
score2 = TestScore1()
|
||||
score2.RocketFarRightBays[0] = BayHatch
|
||||
score2.TeleopCellsInner[0] = 32
|
||||
assert.False(t, score1.Equals(score2))
|
||||
assert.False(t, score2.Equals(score1))
|
||||
|
||||
score2 = TestScore1()
|
||||
score2.RobotEndLevels[1] = 2
|
||||
score2.RotationControl = !score2.RotationControl
|
||||
assert.False(t, score1.Equals(score2))
|
||||
assert.False(t, score2.Equals(score1))
|
||||
|
||||
score2 = TestScore1()
|
||||
score2.PositionControl = !score2.PositionControl
|
||||
assert.False(t, score1.Equals(score2))
|
||||
assert.False(t, score2.Equals(score1))
|
||||
|
||||
score2 = TestScore1()
|
||||
score2.EndgameStatuses[1] = None
|
||||
assert.False(t, score1.Equals(score2))
|
||||
assert.False(t, score2.Equals(score1))
|
||||
|
||||
score2 = TestScore1()
|
||||
score2.RungIsLevel = !score2.RungIsLevel
|
||||
assert.False(t, score1.Equals(score2))
|
||||
assert.False(t, score2.Equals(score1))
|
||||
|
||||
@@ -142,61 +221,3 @@ func TestScoreEquals(t *testing.T) {
|
||||
assert.False(t, score1.Equals(score2))
|
||||
assert.False(t, score2.Equals(score1))
|
||||
}
|
||||
|
||||
func TestIsValidPreMatch(t *testing.T) {
|
||||
score := &Score{}
|
||||
assert.False(t, score.IsValidPreMatch())
|
||||
|
||||
score = TestScoreValidPreMatch()
|
||||
score.RobotStartLevels = [3]int{1, 2, 3}
|
||||
score.CargoBaysPreMatch = [8]BayStatus{1, 3, 3, 0, 0, 1, 1, 3}
|
||||
score.CargoBays = score.CargoBaysPreMatch
|
||||
assert.True(t, score.IsValidPreMatch())
|
||||
|
||||
score = TestScoreValidPreMatch()
|
||||
score.RobotStartLevels[0] = 0
|
||||
assert.False(t, score.IsValidPreMatch())
|
||||
|
||||
score = TestScoreValidPreMatch()
|
||||
score.SandstormBonuses[1] = true
|
||||
assert.False(t, score.IsValidPreMatch())
|
||||
|
||||
score = TestScoreValidPreMatch()
|
||||
score.RobotEndLevels[2] = 3
|
||||
assert.False(t, score.IsValidPreMatch())
|
||||
|
||||
score = TestScoreValidPreMatch()
|
||||
score.CargoBaysPreMatch[0] = BayEmpty
|
||||
assert.False(t, score.IsValidPreMatch())
|
||||
|
||||
score = TestScoreValidPreMatch()
|
||||
score.CargoBaysPreMatch[1] = BayHatchCargo
|
||||
assert.False(t, score.IsValidPreMatch())
|
||||
|
||||
score = TestScoreValidPreMatch()
|
||||
score.CargoBaysPreMatch[3] = BayHatch
|
||||
score.CargoBaysPreMatch[4] = BayCargo
|
||||
score.CargoBaysPreMatch[5] = BayEmpty
|
||||
score.CargoBaysPreMatch[6] = BayEmpty
|
||||
assert.False(t, score.IsValidPreMatch())
|
||||
|
||||
score = TestScoreValidPreMatch()
|
||||
score.CargoBays[0] = BayCargo
|
||||
assert.False(t, score.IsValidPreMatch())
|
||||
|
||||
score = TestScoreValidPreMatch()
|
||||
score.RocketNearLeftBays[0] = BayHatch
|
||||
assert.False(t, score.IsValidPreMatch())
|
||||
|
||||
score = TestScoreValidPreMatch()
|
||||
score.RocketNearRightBays[1] = BayHatchCargo
|
||||
assert.False(t, score.IsValidPreMatch())
|
||||
|
||||
score = TestScoreValidPreMatch()
|
||||
score.RocketFarLeftBays[2] = BayCargo
|
||||
assert.False(t, score.IsValidPreMatch())
|
||||
|
||||
score = TestScoreValidPreMatch()
|
||||
score.RocketFarRightBays[0] = BayHatchCargo
|
||||
assert.False(t, score.IsValidPreMatch())
|
||||
}
|
||||
|
||||
@@ -12,52 +12,46 @@ func TestScore1() *Score {
|
||||
{21, 25, 25.2},
|
||||
}
|
||||
return &Score{
|
||||
RobotStartLevels: [3]int{2, 1, 2},
|
||||
SandstormBonuses: [3]bool{true, true, false},
|
||||
CargoBaysPreMatch: [8]BayStatus{BayHatch, BayEmpty, BayEmpty, BayCargo, BayHatch, BayCargo, BayHatch,
|
||||
BayHatch},
|
||||
CargoBays: [8]BayStatus{BayHatchCargo, BayHatch, BayEmpty, BayHatchCargo, BayHatchCargo, BayEmpty,
|
||||
BayHatch, BayHatchCargo},
|
||||
RocketNearLeftBays: [3]BayStatus{BayHatchCargo, BayEmpty, BayHatchCargo},
|
||||
RocketNearRightBays: [3]BayStatus{BayHatchCargo, BayHatch, BayHatchCargo},
|
||||
RocketFarLeftBays: [3]BayStatus{BayEmpty, BayHatchCargo, BayHatch},
|
||||
RocketFarRightBays: [3]BayStatus{BayEmpty, BayHatchCargo, BayEmpty},
|
||||
RobotEndLevels: [3]int{0, 0, 3},
|
||||
Fouls: fouls,
|
||||
ElimDq: false,
|
||||
ExitedInitiationLine: [3]bool{true, true, false},
|
||||
AutoCellsBottom: [2]int{2, 1},
|
||||
AutoCellsOuter: [2]int{6, 0},
|
||||
AutoCellsInner: [2]int{4, 5},
|
||||
TeleopPeriodStarted: true,
|
||||
TeleopCellsBottom: [4]int{0, 11, 2, 0},
|
||||
TeleopCellsOuter: [4]int{0, 5, 0, 0},
|
||||
TeleopCellsInner: [4]int{0, 5, 0, 0},
|
||||
RotationControl: true,
|
||||
PositionControl: false,
|
||||
EndgameStatuses: [3]EndgameStatus{Hang, Hang, Hang},
|
||||
RungIsLevel: false,
|
||||
Fouls: fouls,
|
||||
ElimDq: false,
|
||||
}
|
||||
}
|
||||
|
||||
func TestScore2() *Score {
|
||||
return &Score{
|
||||
RobotStartLevels: [3]int{1, 2, 1},
|
||||
SandstormBonuses: [3]bool{false, true, false},
|
||||
CargoBaysPreMatch: [8]BayStatus{BayEmpty, BayEmpty, BayHatch, BayHatch, BayHatch, BayHatch, BayHatch,
|
||||
BayHatch},
|
||||
CargoBays: [8]BayStatus{BayEmpty, BayEmpty, BayHatchCargo, BayHatchCargo, BayHatchCargo, BayHatch, BayHatch,
|
||||
BayHatchCargo},
|
||||
RocketNearLeftBays: [3]BayStatus{BayEmpty, BayEmpty, BayEmpty},
|
||||
RocketNearRightBays: [3]BayStatus{BayEmpty, BayEmpty, BayEmpty},
|
||||
RocketFarLeftBays: [3]BayStatus{BayHatchCargo, BayEmpty, BayEmpty},
|
||||
RocketFarRightBays: [3]BayStatus{BayEmpty, BayEmpty, BayHatchCargo},
|
||||
RobotEndLevels: [3]int{1, 3, 2},
|
||||
Fouls: []Foul{},
|
||||
ElimDq: false,
|
||||
}
|
||||
}
|
||||
|
||||
func TestScoreValidPreMatch() *Score {
|
||||
return &Score{
|
||||
RobotStartLevels: [3]int{1, 2, 3},
|
||||
CargoBaysPreMatch: [8]BayStatus{1, 3, 3, 0, 0, 1, 1, 3},
|
||||
CargoBays: [8]BayStatus{1, 3, 3, 0, 0, 1, 1, 3},
|
||||
ExitedInitiationLine: [3]bool{false, true, false},
|
||||
AutoCellsBottom: [2]int{0, 0},
|
||||
AutoCellsOuter: [2]int{3, 0},
|
||||
AutoCellsInner: [2]int{0, 0},
|
||||
TeleopPeriodStarted: true,
|
||||
TeleopCellsBottom: [4]int{2, 0, 2, 0},
|
||||
TeleopCellsOuter: [4]int{2, 14, 0, 1},
|
||||
TeleopCellsInner: [4]int{2, 6, 20, 0},
|
||||
RotationControl: true,
|
||||
PositionControl: true,
|
||||
EndgameStatuses: [3]EndgameStatus{Park, Park, Hang},
|
||||
RungIsLevel: true,
|
||||
Fouls: []Foul{},
|
||||
ElimDq: false,
|
||||
}
|
||||
}
|
||||
|
||||
func TestRanking1() *Ranking {
|
||||
return &Ranking{254, 1, RankingFields{20, 625, 90, 554, 10, 0.254, 3, 2, 1, 0, 10}}
|
||||
return &Ranking{254, 1, RankingFields{20, 625, 90, 554, 0.254, 3, 2, 1, 0, 10}}
|
||||
}
|
||||
|
||||
func TestRanking2() *Ranking {
|
||||
return &Ranking{1114, 2, RankingFields{18, 700, 625, 90, 554, 0.1114, 1, 3, 2, 0, 10}}
|
||||
return &Ranking{1114, 2, RankingFields{18, 700, 625, 90, 0.1114, 1, 3, 2, 0, 10}}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/game"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
@@ -25,7 +26,7 @@ func TestMatchResultCrud(t *testing.T) {
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, matchResult, matchResult2)
|
||||
|
||||
matchResult.BlueScore.RobotEndLevels = [3]int{3, 3, 3}
|
||||
matchResult.BlueScore.EndgameStatuses = [3]game.EndgameStatus{game.Hang, game.None, game.Park}
|
||||
db.SaveMatchResult(matchResult)
|
||||
matchResult2, err = db.GetMatchResultForMatch(254)
|
||||
assert.Nil(t, err)
|
||||
|
||||
137
partner/tba.go
137
partner/tba.go
@@ -11,7 +11,6 @@ import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/Team254/cheesy-arena/game"
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@@ -101,10 +100,9 @@ type TbaRanking struct {
|
||||
TeamKey string `json:"team_key"`
|
||||
Rank int `json:"rank"`
|
||||
RP float32
|
||||
ParkClimb int
|
||||
Auto int
|
||||
Ownership int
|
||||
Vault int
|
||||
Endgame int
|
||||
Teleop int
|
||||
WinLossTie string
|
||||
Dqs int `json:"dqs"`
|
||||
Played int `json:"played"`
|
||||
@@ -386,12 +384,12 @@ func (client *TbaClient) PublishRankings(database *model.Database) error {
|
||||
}
|
||||
|
||||
// Build a JSON object of TBA-format rankings.
|
||||
breakdowns := []string{"RP", "ParkClimb", "Auto", "Ownership", "Vault", "WinLossTie"}
|
||||
breakdowns := []string{"RP", "Auto", "Endgame", "Teleop", "WinLossTie"}
|
||||
tbaRankings := make([]TbaRanking, len(rankings))
|
||||
for i, ranking := range rankings {
|
||||
tbaRankings[i] = TbaRanking{getTbaTeam(ranking.TeamId), ranking.Rank,
|
||||
float32(ranking.RankingPoints) / float32(ranking.Played), ranking.CargoPoints, ranking.HatchPanelPoints,
|
||||
ranking.HabClimbPoints, ranking.SandstormBonusPoints,
|
||||
float32(ranking.RankingPoints) / float32(ranking.Played), ranking.AutoPoints, ranking.EndgamePoints,
|
||||
ranking.TeleopPoints,
|
||||
fmt.Sprintf("%d-%d-%d", ranking.Wins, ranking.Losses, ranking.Ties), ranking.Disqualifications,
|
||||
ranking.Played}
|
||||
}
|
||||
@@ -534,68 +532,71 @@ func createTbaAlliance(teamIds [3]int, surrogates [3]bool, score *int, cards map
|
||||
|
||||
func createTbaScoringBreakdown(match *model.Match, matchResult *model.MatchResult, alliance string) *TbaScoreBreakdown {
|
||||
var breakdown TbaScoreBreakdown
|
||||
var score *game.Score
|
||||
var scoreSummary, opponentScoreSummary *game.ScoreSummary
|
||||
if alliance == "red" {
|
||||
score = matchResult.RedScore
|
||||
scoreSummary = matchResult.RedScoreSummary()
|
||||
opponentScoreSummary = matchResult.BlueScoreSummary()
|
||||
} else {
|
||||
score = matchResult.BlueScore
|
||||
scoreSummary = matchResult.BlueScoreSummary()
|
||||
opponentScoreSummary = matchResult.RedScoreSummary()
|
||||
}
|
||||
// TODO(pat): Update for 2020.
|
||||
/*
|
||||
var score *game.Score
|
||||
var scoreSummary, opponentScoreSummary *game.ScoreSummary
|
||||
if alliance == "red" {
|
||||
score = matchResult.RedScore
|
||||
scoreSummary = matchResult.RedScoreSummary()
|
||||
opponentScoreSummary = matchResult.BlueScoreSummary()
|
||||
} else {
|
||||
score = matchResult.BlueScore
|
||||
scoreSummary = matchResult.BlueScoreSummary()
|
||||
opponentScoreSummary = matchResult.RedScoreSummary()
|
||||
}
|
||||
|
||||
breakdown.PreMatchLevelRobot1 = habLevelMapping[score.RobotStartLevels[0]]
|
||||
breakdown.PreMatchLevelRobot2 = habLevelMapping[score.RobotStartLevels[1]]
|
||||
breakdown.PreMatchLevelRobot3 = habLevelMapping[score.RobotStartLevels[2]]
|
||||
breakdown.PreMatchBay1 = bayStatusMapping[score.CargoBaysPreMatch[0]]
|
||||
breakdown.PreMatchBay2 = bayStatusMapping[score.CargoBaysPreMatch[1]]
|
||||
breakdown.PreMatchBay3 = bayStatusMapping[score.CargoBaysPreMatch[2]]
|
||||
breakdown.PreMatchBay6 = bayStatusMapping[score.CargoBaysPreMatch[5]]
|
||||
breakdown.PreMatchBay7 = bayStatusMapping[score.CargoBaysPreMatch[6]]
|
||||
breakdown.PreMatchBay8 = bayStatusMapping[score.CargoBaysPreMatch[7]]
|
||||
breakdown.HabLineRobot1 = sandstormBonusMapping[score.SandstormBonuses[0]]
|
||||
breakdown.HabLineRobot2 = sandstormBonusMapping[score.SandstormBonuses[1]]
|
||||
breakdown.HabLineRobot3 = sandstormBonusMapping[score.SandstormBonuses[2]]
|
||||
breakdown.SandstormBonusPoints = scoreSummary.SandstormBonusPoints
|
||||
breakdown.Bay1 = bayStatusMapping[score.CargoBays[0]]
|
||||
breakdown.Bay2 = bayStatusMapping[score.CargoBays[1]]
|
||||
breakdown.Bay3 = bayStatusMapping[score.CargoBays[2]]
|
||||
breakdown.Bay4 = bayStatusMapping[score.CargoBays[3]]
|
||||
breakdown.Bay5 = bayStatusMapping[score.CargoBays[4]]
|
||||
breakdown.Bay6 = bayStatusMapping[score.CargoBays[5]]
|
||||
breakdown.Bay7 = bayStatusMapping[score.CargoBays[6]]
|
||||
breakdown.Bay8 = bayStatusMapping[score.CargoBays[7]]
|
||||
breakdown.LowLeftRocketNear = bayStatusMapping[score.RocketNearLeftBays[0]]
|
||||
breakdown.MidLeftRocketNear = bayStatusMapping[score.RocketNearLeftBays[1]]
|
||||
breakdown.TopLeftRocketNear = bayStatusMapping[score.RocketNearLeftBays[2]]
|
||||
breakdown.LowRightRocketNear = bayStatusMapping[score.RocketNearRightBays[0]]
|
||||
breakdown.MidRightRocketNear = bayStatusMapping[score.RocketNearRightBays[1]]
|
||||
breakdown.TopRightRocketNear = bayStatusMapping[score.RocketNearRightBays[2]]
|
||||
breakdown.LowLeftRocketFar = bayStatusMapping[score.RocketFarLeftBays[0]]
|
||||
breakdown.MidLeftRocketFar = bayStatusMapping[score.RocketFarLeftBays[1]]
|
||||
breakdown.TopLeftRocketFar = bayStatusMapping[score.RocketFarLeftBays[2]]
|
||||
breakdown.LowRightRocketFar = bayStatusMapping[score.RocketFarRightBays[0]]
|
||||
breakdown.MidRightRocketFar = bayStatusMapping[score.RocketFarRightBays[1]]
|
||||
breakdown.TopRightRocketFar = bayStatusMapping[score.RocketFarRightBays[2]]
|
||||
breakdown.CargoPoints = scoreSummary.CargoPoints
|
||||
breakdown.HatchPanelPoints = scoreSummary.HatchPanelPoints
|
||||
breakdown.EndgameRobot1 = habLevelMapping[score.RobotEndLevels[0]]
|
||||
breakdown.EndgameRobot2 = habLevelMapping[score.RobotEndLevels[1]]
|
||||
breakdown.EndgameRobot3 = habLevelMapping[score.RobotEndLevels[2]]
|
||||
breakdown.HabClimbPoints = scoreSummary.HabClimbPoints
|
||||
breakdown.TeleopPoints = scoreSummary.CargoPoints + scoreSummary.HatchPanelPoints + scoreSummary.HabClimbPoints
|
||||
breakdown.CompleteRocketRankingPoint = scoreSummary.CompleteRocket
|
||||
breakdown.HabDockingRankingPoint = scoreSummary.HabDocking
|
||||
breakdown.FoulPoints = scoreSummary.FoulPoints
|
||||
breakdown.TotalPoints = scoreSummary.Score
|
||||
if match.ShouldUpdateRankings() {
|
||||
// Calculate and set the ranking points for the match.
|
||||
var ranking game.Ranking
|
||||
ranking.AddScoreSummary(scoreSummary, opponentScoreSummary, false)
|
||||
breakdown.RP = ranking.RankingPoints
|
||||
}
|
||||
breakdown.PreMatchLevelRobot1 = habLevelMapping[score.RobotStartLevels[0]]
|
||||
breakdown.PreMatchLevelRobot2 = habLevelMapping[score.RobotStartLevels[1]]
|
||||
breakdown.PreMatchLevelRobot3 = habLevelMapping[score.RobotStartLevels[2]]
|
||||
breakdown.PreMatchBay1 = bayStatusMapping[score.CargoBaysPreMatch[0]]
|
||||
breakdown.PreMatchBay2 = bayStatusMapping[score.CargoBaysPreMatch[1]]
|
||||
breakdown.PreMatchBay3 = bayStatusMapping[score.CargoBaysPreMatch[2]]
|
||||
breakdown.PreMatchBay6 = bayStatusMapping[score.CargoBaysPreMatch[5]]
|
||||
breakdown.PreMatchBay7 = bayStatusMapping[score.CargoBaysPreMatch[6]]
|
||||
breakdown.PreMatchBay8 = bayStatusMapping[score.CargoBaysPreMatch[7]]
|
||||
breakdown.HabLineRobot1 = sandstormBonusMapping[score.SandstormBonuses[0]]
|
||||
breakdown.HabLineRobot2 = sandstormBonusMapping[score.SandstormBonuses[1]]
|
||||
breakdown.HabLineRobot3 = sandstormBonusMapping[score.SandstormBonuses[2]]
|
||||
breakdown.SandstormBonusPoints = scoreSummary.SandstormBonusPoints
|
||||
breakdown.Bay1 = bayStatusMapping[score.CargoBays[0]]
|
||||
breakdown.Bay2 = bayStatusMapping[score.CargoBays[1]]
|
||||
breakdown.Bay3 = bayStatusMapping[score.CargoBays[2]]
|
||||
breakdown.Bay4 = bayStatusMapping[score.CargoBays[3]]
|
||||
breakdown.Bay5 = bayStatusMapping[score.CargoBays[4]]
|
||||
breakdown.Bay6 = bayStatusMapping[score.CargoBays[5]]
|
||||
breakdown.Bay7 = bayStatusMapping[score.CargoBays[6]]
|
||||
breakdown.Bay8 = bayStatusMapping[score.CargoBays[7]]
|
||||
breakdown.LowLeftRocketNear = bayStatusMapping[score.RocketNearLeftBays[0]]
|
||||
breakdown.MidLeftRocketNear = bayStatusMapping[score.RocketNearLeftBays[1]]
|
||||
breakdown.TopLeftRocketNear = bayStatusMapping[score.RocketNearLeftBays[2]]
|
||||
breakdown.LowRightRocketNear = bayStatusMapping[score.RocketNearRightBays[0]]
|
||||
breakdown.MidRightRocketNear = bayStatusMapping[score.RocketNearRightBays[1]]
|
||||
breakdown.TopRightRocketNear = bayStatusMapping[score.RocketNearRightBays[2]]
|
||||
breakdown.LowLeftRocketFar = bayStatusMapping[score.RocketFarLeftBays[0]]
|
||||
breakdown.MidLeftRocketFar = bayStatusMapping[score.RocketFarLeftBays[1]]
|
||||
breakdown.TopLeftRocketFar = bayStatusMapping[score.RocketFarLeftBays[2]]
|
||||
breakdown.LowRightRocketFar = bayStatusMapping[score.RocketFarRightBays[0]]
|
||||
breakdown.MidRightRocketFar = bayStatusMapping[score.RocketFarRightBays[1]]
|
||||
breakdown.TopRightRocketFar = bayStatusMapping[score.RocketFarRightBays[2]]
|
||||
breakdown.CargoPoints = scoreSummary.CargoPoints
|
||||
breakdown.HatchPanelPoints = scoreSummary.HatchPanelPoints
|
||||
breakdown.EndgameRobot1 = habLevelMapping[score.RobotEndLevels[0]]
|
||||
breakdown.EndgameRobot2 = habLevelMapping[score.RobotEndLevels[1]]
|
||||
breakdown.EndgameRobot3 = habLevelMapping[score.RobotEndLevels[2]]
|
||||
breakdown.HabClimbPoints = scoreSummary.HabClimbPoints
|
||||
breakdown.TeleopPoints = scoreSummary.CargoPoints + scoreSummary.HatchPanelPoints + scoreSummary.HabClimbPoints
|
||||
breakdown.CompleteRocketRankingPoint = scoreSummary.CompleteRocket
|
||||
breakdown.HabDockingRankingPoint = scoreSummary.HabDocking
|
||||
breakdown.FoulPoints = scoreSummary.FoulPoints
|
||||
breakdown.TotalPoints = scoreSummary.Score
|
||||
if match.ShouldUpdateRankings() {
|
||||
// Calculate and set the ranking points for the match.
|
||||
var ranking game.Ranking
|
||||
ranking.AddScoreSummary(scoreSummary, opponentScoreSummary, false)
|
||||
breakdown.RP = ranking.RankingPoints
|
||||
}
|
||||
*/
|
||||
|
||||
return &breakdown
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>A field management system that just works.</p>
|
||||
<p>Copyright © 2014-2019 Team 254. All Rights Reserved.</p>
|
||||
<p>Copyright © 2014-2020 Team 254. All Rights Reserved.</p>
|
||||
<p><a href="https://github.com/Team254/cheesy-arena">https://github.com/Team254/cheesy-arena</a></p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
Rank,TeamId,RankingPoints,CargoPoints,HatchPanelPoints,HabClimbPoints,SandstormBonusPoints,Wins,Losses,Ties,Disqualifications,Played
|
||||
{{range $ranking := .}}{{$ranking.Rank}},{{$ranking.TeamId}},{{$ranking.RankingPoints}},{{$ranking.CargoPoints}},{{$ranking.HatchPanelPoints}},{{$ranking.HabClimbPoints}},{{$ranking.SandstormBonusPoints}},{{$ranking.Wins}},{{$ranking.Losses}},{{$ranking.Ties}},{{$ranking.Disqualifications}},{{$ranking.Played}}
|
||||
{{range $ranking := .}}{{$ranking.Rank}},{{$ranking.TeamId}},{{$ranking.RankingPoints}},{{$ranking.AutoPoints}},{{$ranking.EndgamePoints}},{{$ranking.TeleopPoints}},{{$ranking.Wins}},{{$ranking.Losses}},{{$ranking.Ties}},{{$ranking.Disqualifications}},{{$ranking.Played}}
|
||||
{{end}}
|
||||
|
||||
|
@@ -133,7 +133,7 @@ func TestCommitMatch(t *testing.T) {
|
||||
web.arena.Database.CreateMatch(match)
|
||||
matchResult = model.NewMatchResult()
|
||||
matchResult.MatchId = match.Id
|
||||
matchResult.BlueScore = &game.Score{RobotEndLevels: [3]int{3, 3, 3}}
|
||||
matchResult.BlueScore = &game.Score{ExitedInitiationLine: [3]bool{true, false, false}}
|
||||
err = web.commitMatchScore(match, matchResult, false)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 1, matchResult.PlayNumber)
|
||||
@@ -142,7 +142,7 @@ func TestCommitMatch(t *testing.T) {
|
||||
|
||||
matchResult = model.NewMatchResult()
|
||||
matchResult.MatchId = match.Id
|
||||
matchResult.RedScore = &game.Score{RobotEndLevels: [3]int{2, 2, 2}}
|
||||
matchResult.RedScore = &game.Score{ExitedInitiationLine: [3]bool{true, false, true}}
|
||||
err = web.commitMatchScore(match, matchResult, false)
|
||||
assert.Nil(t, err)
|
||||
assert.Equal(t, 2, matchResult.PlayNumber)
|
||||
@@ -177,8 +177,8 @@ func TestCommitEliminationTie(t *testing.T) {
|
||||
matchResult := &model.MatchResult{
|
||||
MatchId: match.Id,
|
||||
RedScore: &game.Score{
|
||||
RocketFarRightBays: [3]game.BayStatus{game.BayHatchCargo, game.BayHatch, game.BayHatch},
|
||||
Fouls: []game.Foul{{RuleId: 1}, {RuleId: 2}, {RuleId: 4}}},
|
||||
TeleopCellsInner: [4]int{1, 2, 0, 0},
|
||||
Fouls: []game.Foul{{RuleId: 1}, {RuleId: 2}, {RuleId: 4}}},
|
||||
BlueScore: &game.Score{},
|
||||
}
|
||||
err := web.commitMatchScore(match, matchResult, false)
|
||||
@@ -309,12 +309,12 @@ func TestMatchPlayWebsocketCommands(t *testing.T) {
|
||||
readWebsocketType(t, ws, "audienceDisplayMode")
|
||||
readWebsocketType(t, ws, "allianceStationDisplayMode")
|
||||
assert.Equal(t, field.PostMatch, web.arena.MatchState)
|
||||
web.arena.RedRealtimeScore.CurrentScore.RobotEndLevels = [3]int{1, 2, 3}
|
||||
web.arena.BlueRealtimeScore.CurrentScore.SandstormBonuses = [3]bool{true, false, true}
|
||||
web.arena.RedRealtimeScore.CurrentScore.TeleopCellsOuter = [4]int{1, 1, 1, 4}
|
||||
web.arena.BlueRealtimeScore.CurrentScore.ExitedInitiationLine = [3]bool{true, false, true}
|
||||
ws.Write("commitResults", nil)
|
||||
readWebsocketMultiple(t, ws, 3) // reload, realtimeScore, setAllianceStationDisplay
|
||||
assert.Equal(t, [3]int{1, 2, 3}, web.arena.SavedMatchResult.RedScore.RobotEndLevels)
|
||||
assert.Equal(t, [3]bool{true, false, true}, web.arena.SavedMatchResult.BlueScore.SandstormBonuses)
|
||||
assert.Equal(t, [4]int{1, 1, 1, 4}, web.arena.SavedMatchResult.RedScore.TeleopCellsOuter)
|
||||
assert.Equal(t, [3]bool{true, false, true}, web.arena.SavedMatchResult.BlueScore.ExitedInitiationLine)
|
||||
assert.Equal(t, field.PreMatch, web.arena.MatchState)
|
||||
ws.Write("discardResults", nil)
|
||||
readWebsocketMultiple(t, ws, 3) // reload, realtimeScore, setAllianceStationDisplay
|
||||
|
||||
@@ -49,8 +49,8 @@ func TestMatchReviewEditExistingResult(t *testing.T) {
|
||||
recorder := web.getHttpResponse("/match_review")
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Contains(t, recorder.Body.String(), ">QF4-3<")
|
||||
assert.Contains(t, recorder.Body.String(), ">71<") // The red score
|
||||
assert.Contains(t, recorder.Body.String(), ">72<") // The blue score
|
||||
assert.Contains(t, recorder.Body.String(), ">217<") // The red score
|
||||
assert.Contains(t, recorder.Body.String(), ">252<") // The blue score
|
||||
|
||||
// Check response for non-existent match.
|
||||
recorder = web.getHttpResponse(fmt.Sprintf("/match_review/%d/edit", 12345))
|
||||
@@ -62,17 +62,18 @@ func TestMatchReviewEditExistingResult(t *testing.T) {
|
||||
assert.Contains(t, recorder.Body.String(), " QF4-3 ")
|
||||
|
||||
// Update the score to something else.
|
||||
postBody := "redScoreJson={\"RobotEndLevels\":[0,3,0]}&blueScoreJson={\"CargoBays\":[0,2,1,2,2,0,1]," +
|
||||
postBody := "redScoreJson={\"RobotEndLevels\":[0,3,0]}&blueScoreJson={\"AutoCellsOuter\":[3, 4]," +
|
||||
"\"Fouls\":[{\"TeamId\":973,\"RuleId\":1}]}&redCardsJson={\"105\":\"yellow\"}&blueCardsJson={}"
|
||||
recorder = web.postHttpResponse(fmt.Sprintf("/match_review/%d/edit", match.Id), postBody)
|
||||
assert.Equal(t, 303, recorder.Code)
|
||||
|
||||
// TODO(pat): Update for 2020.
|
||||
// Check for the updated scores back on the match list page.
|
||||
recorder = web.getHttpResponse("/match_review")
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Contains(t, recorder.Body.String(), ">QF4-3<")
|
||||
assert.Contains(t, recorder.Body.String(), ">15<") // The red score
|
||||
assert.Contains(t, recorder.Body.String(), ">19<") // The blue score
|
||||
assert.Contains(t, recorder.Body.String(), ">0<") // The red score
|
||||
assert.Contains(t, recorder.Body.String(), ">0<") // The blue score
|
||||
}
|
||||
|
||||
func TestMatchReviewCreateNewResult(t *testing.T) {
|
||||
@@ -99,10 +100,11 @@ func TestMatchReviewCreateNewResult(t *testing.T) {
|
||||
recorder = web.postHttpResponse(fmt.Sprintf("/match_review/%d/edit", match.Id), postBody)
|
||||
assert.Equal(t, 303, recorder.Code)
|
||||
|
||||
// TODO(pat): Update for 2020.
|
||||
// Check for the updated scores back on the match list page.
|
||||
recorder = web.getHttpResponse("/match_review")
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Contains(t, recorder.Body.String(), ">QF4-3<")
|
||||
assert.Contains(t, recorder.Body.String(), ">10<") // The red score
|
||||
assert.Contains(t, recorder.Body.String(), ">15<") // The blue score
|
||||
assert.Contains(t, recorder.Body.String(), ">0<") // The red score
|
||||
assert.Contains(t, recorder.Body.String(), ">0<") // The blue score
|
||||
}
|
||||
|
||||
@@ -73,12 +73,9 @@ func (web *Web) rankingsPdfReportHandler(w http.ResponseWriter, r *http.Request)
|
||||
pdf.SetFont("Arial", "", 10)
|
||||
pdf.CellFormat(colWidths["Team"], rowHeight, strconv.Itoa(ranking.TeamId), "1", 0, "C", false, 0, "")
|
||||
pdf.CellFormat(colWidths["RP"], rowHeight, strconv.Itoa(ranking.RankingPoints), "1", 0, "C", false, 0, "")
|
||||
pdf.CellFormat(colWidths["Cargo"], rowHeight, strconv.Itoa(ranking.CargoPoints), "1", 0, "C", false, 0, "")
|
||||
pdf.CellFormat(colWidths["Hatch"], rowHeight, strconv.Itoa(ranking.HatchPanelPoints), "1", 0, "C", false, 0, "")
|
||||
pdf.CellFormat(colWidths["Hab Climb"], rowHeight, strconv.Itoa(ranking.HabClimbPoints), "1", 0, "C", false, 0,
|
||||
"")
|
||||
pdf.CellFormat(colWidths["Sandstorm"], rowHeight, strconv.Itoa(ranking.SandstormBonusPoints), "1", 0, "C",
|
||||
false, 0, "")
|
||||
pdf.CellFormat(colWidths["Cargo"], rowHeight, strconv.Itoa(ranking.AutoPoints), "1", 0, "C", false, 0, "")
|
||||
pdf.CellFormat(colWidths["Hatch"], rowHeight, strconv.Itoa(ranking.EndgamePoints), "1", 0, "C", false, 0, "")
|
||||
pdf.CellFormat(colWidths["Hab Climb"], rowHeight, strconv.Itoa(ranking.TeleopPoints), "1", 0, "C", false, 0, "")
|
||||
record := fmt.Sprintf("%d-%d-%d", ranking.Wins, ranking.Losses, ranking.Ties)
|
||||
pdf.CellFormat(colWidths["W-L-T"], rowHeight, record, "1", 0, "C", false, 0, "")
|
||||
pdf.CellFormat(colWidths["DQ"], rowHeight, strconv.Itoa(ranking.Disqualifications), "1", 0, "C", false, 0, "")
|
||||
|
||||
@@ -23,7 +23,7 @@ func TestRankingsCsvReport(t *testing.T) {
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Equal(t, "text/plain", recorder.HeaderMap["Content-Type"][0])
|
||||
expectedBody := "Rank,TeamId,RankingPoints,CargoPoints,HatchPanelPoints,HabClimbPoints,SandstormBonusPoints,Wins," +
|
||||
"Losses,Ties,Disqualifications,Played\n1,254,20,625,90,554,10,3,2,1,0,10\n2,1114,18,700,625,90,554,1,3,2,0,10" +
|
||||
"Losses,Ties,Disqualifications,Played\n1,254,20,625,90,554,3,2,1,0,10\n2,1114,18,700,625,90,1,3,2,0,10" +
|
||||
"\n\n"
|
||||
assert.Equal(t, expectedBody, recorder.Body.String())
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ package web
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Team254/cheesy-arena/field"
|
||||
"github.com/Team254/cheesy-arena/game"
|
||||
"github.com/Team254/cheesy-arena/model"
|
||||
"github.com/Team254/cheesy-arena/websocket"
|
||||
"github.com/gorilla/mux"
|
||||
@@ -93,12 +92,15 @@ func (web *Web) scoringPanelWebsocketHandler(w http.ResponseWriter, r *http.Requ
|
||||
handleWebErr(w, fmt.Errorf("Invalid alliance '%s'.", alliance))
|
||||
return
|
||||
}
|
||||
var realtimeScore **field.RealtimeScore
|
||||
if alliance == "red" {
|
||||
realtimeScore = &web.arena.RedRealtimeScore
|
||||
} else {
|
||||
realtimeScore = &web.arena.BlueRealtimeScore
|
||||
}
|
||||
// TODO(pat): Update for 2020.
|
||||
/*
|
||||
var realtimeScore **field.RealtimeScore
|
||||
if alliance == "red" {
|
||||
realtimeScore = &web.arena.RedRealtimeScore
|
||||
} else {
|
||||
realtimeScore = &web.arena.BlueRealtimeScore
|
||||
}
|
||||
*/
|
||||
|
||||
ws, err := websocket.NewWebsocket(w, r)
|
||||
if err != nil {
|
||||
@@ -127,7 +129,8 @@ func (web *Web) scoringPanelWebsocketHandler(w http.ResponseWriter, r *http.Requ
|
||||
return
|
||||
}
|
||||
|
||||
score := &(*realtimeScore).CurrentScore
|
||||
// TODO(pat): Update for 2020.
|
||||
//score := &(*realtimeScore).CurrentScore
|
||||
scoreChanged := false
|
||||
|
||||
if command == "commitMatch" {
|
||||
@@ -139,27 +142,30 @@ func (web *Web) scoringPanelWebsocketHandler(w http.ResponseWriter, r *http.Requ
|
||||
web.arena.ScoringPanelRegistry.SetScoreCommitted(alliance, ws)
|
||||
web.arena.ScoringStatusNotifier.Notify()
|
||||
} else if number, err := strconv.Atoi(command); err == nil && number >= 1 && number <= 9 {
|
||||
// Handle per-robot scoring fields.
|
||||
if number <= 3 && web.arena.MatchState == field.PreMatch {
|
||||
index := number - 1
|
||||
score.RobotStartLevels[index]++
|
||||
if score.RobotStartLevels[index] == 4 {
|
||||
score.RobotStartLevels[index] = 0
|
||||
// TODO(pat): Update for 2020.
|
||||
/*
|
||||
// Handle per-robot scoring fields.
|
||||
if number <= 3 && web.arena.MatchState == field.PreMatch {
|
||||
index := number - 1
|
||||
score.RobotStartLevels[index]++
|
||||
if score.RobotStartLevels[index] == 4 {
|
||||
score.RobotStartLevels[index] = 0
|
||||
}
|
||||
scoreChanged = true
|
||||
} else if number > 3 && number <= 6 && web.arena.MatchState != field.PreMatch {
|
||||
index := number - 4
|
||||
score.SandstormBonuses[index] =
|
||||
!score.SandstormBonuses[index]
|
||||
scoreChanged = true
|
||||
} else if number > 6 && web.arena.MatchState != field.PreMatch {
|
||||
index := number - 7
|
||||
score.RobotEndLevels[index]++
|
||||
if score.RobotEndLevels[index] == 4 {
|
||||
score.RobotEndLevels[index] = 0
|
||||
}
|
||||
scoreChanged = true
|
||||
}
|
||||
scoreChanged = true
|
||||
} else if number > 3 && number <= 6 && web.arena.MatchState != field.PreMatch {
|
||||
index := number - 4
|
||||
score.SandstormBonuses[index] =
|
||||
!score.SandstormBonuses[index]
|
||||
scoreChanged = true
|
||||
} else if number > 6 && web.arena.MatchState != field.PreMatch {
|
||||
index := number - 7
|
||||
score.RobotEndLevels[index]++
|
||||
if score.RobotEndLevels[index] == 4 {
|
||||
score.RobotEndLevels[index] = 0
|
||||
}
|
||||
scoreChanged = true
|
||||
}
|
||||
*/
|
||||
} else {
|
||||
// Handle cargo bays.
|
||||
var bayMapping *bayMapping
|
||||
@@ -170,36 +176,38 @@ func (web *Web) scoringPanelWebsocketHandler(w http.ResponseWriter, r *http.Requ
|
||||
}
|
||||
}
|
||||
if bayMapping != nil {
|
||||
element := bayMapping.RedElement
|
||||
index := bayMapping.RedIndex
|
||||
if alliance == "blue" {
|
||||
element = bayMapping.BlueElement
|
||||
index = bayMapping.BlueIndex
|
||||
}
|
||||
switch element {
|
||||
case "cargoShip":
|
||||
scoreChanged = web.toggleCargoShipBay(&score.CargoBays[index], index)
|
||||
case "rocketNearLeft":
|
||||
scoreChanged = web.toggleRocketBay(&score.RocketNearLeftBays[index])
|
||||
case "rocketNearRight":
|
||||
scoreChanged = web.toggleRocketBay(&score.RocketNearRightBays[index])
|
||||
case "rocketFarLeft":
|
||||
scoreChanged = web.toggleRocketBay(&score.RocketFarLeftBays[index])
|
||||
case "rocketFarRight":
|
||||
scoreChanged = web.toggleRocketBay(&score.RocketFarRightBays[index])
|
||||
}
|
||||
// TODO(pat): Update for 2020.
|
||||
/*
|
||||
element := bayMapping.RedElement
|
||||
index := bayMapping.RedIndex
|
||||
if alliance == "blue" {
|
||||
element = bayMapping.BlueElement
|
||||
index = bayMapping.BlueIndex
|
||||
}
|
||||
switch element {
|
||||
case "cargoShip":
|
||||
scoreChanged = web.toggleCargoShipBay(&score.CargoBays[index], index)
|
||||
case "rocketNearLeft":
|
||||
scoreChanged = web.toggleRocketBay(&score.RocketNearLeftBays[index])
|
||||
case "rocketNearRight":
|
||||
scoreChanged = web.toggleRocketBay(&score.RocketNearRightBays[index])
|
||||
case "rocketFarLeft":
|
||||
scoreChanged = web.toggleRocketBay(&score.RocketFarLeftBays[index])
|
||||
case "rocketFarRight":
|
||||
scoreChanged = web.toggleRocketBay(&score.RocketFarRightBays[index])
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
if scoreChanged {
|
||||
if web.arena.MatchState == field.PreMatch {
|
||||
score.CargoBaysPreMatch = score.CargoBays
|
||||
}
|
||||
web.arena.RealtimeScoreNotifier.Notify()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(pat): Update for 2020.
|
||||
/*
|
||||
// Advances the given cargo ship bay through the states applicable to the current status of the field.
|
||||
func (web *Web) toggleCargoShipBay(bay *game.BayStatus, index int) bool {
|
||||
if (index == 3 || index == 4) && web.arena.MatchState == field.PreMatch {
|
||||
@@ -242,3 +250,4 @@ func (web *Web) toggleRocketBay(bay *game.BayStatus) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -5,7 +5,6 @@ package web
|
||||
|
||||
import (
|
||||
"github.com/Team254/cheesy-arena/field"
|
||||
"github.com/Team254/cheesy-arena/game"
|
||||
"github.com/Team254/cheesy-arena/websocket"
|
||||
gorillawebsocket "github.com/gorilla/websocket"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -54,53 +53,56 @@ func TestScoringPanelWebsocket(t *testing.T) {
|
||||
readWebsocketType(t, blueWs, "matchTime")
|
||||
readWebsocketType(t, blueWs, "realtimeScore")
|
||||
|
||||
// Send a some pre-match scoring commands.
|
||||
redWs.Write("1", nil)
|
||||
blueWs.Write("2", nil)
|
||||
blueWs.Write("2", nil)
|
||||
blueWs.Write("2", nil)
|
||||
blueWs.Write("2", nil)
|
||||
for i := 0; i < 5; i++ {
|
||||
readWebsocketType(t, redWs, "realtimeScore")
|
||||
readWebsocketType(t, blueWs, "realtimeScore")
|
||||
}
|
||||
assert.Equal(t, 1, web.arena.RedRealtimeScore.CurrentScore.RobotStartLevels[0])
|
||||
assert.Equal(t, 0, web.arena.BlueRealtimeScore.CurrentScore.RobotStartLevels[1])
|
||||
redWs.Write("e", nil)
|
||||
redWs.Write("i", nil)
|
||||
redWs.Write("i", nil)
|
||||
redWs.Write("v", nil)
|
||||
redWs.Write("q", nil)
|
||||
redWs.Write(",", nil)
|
||||
for i := 0; i < 3; i++ {
|
||||
readWebsocketType(t, redWs, "realtimeScore")
|
||||
readWebsocketType(t, blueWs, "realtimeScore")
|
||||
}
|
||||
assert.Equal(t, [8]game.BayStatus{1, 0, 0, 0, 0, 0, 0, 3},
|
||||
web.arena.RedRealtimeScore.CurrentScore.CargoBaysPreMatch)
|
||||
assert.Equal(t, [8]game.BayStatus{1, 0, 0, 0, 0, 0, 0, 3}, web.arena.RedRealtimeScore.CurrentScore.CargoBays)
|
||||
assert.Equal(t, [3]game.BayStatus{0, 0, 0}, web.arena.RedRealtimeScore.CurrentScore.RocketNearLeftBays)
|
||||
assert.Equal(t, [3]game.BayStatus{0, 0, 0}, web.arena.RedRealtimeScore.CurrentScore.RocketNearRightBays)
|
||||
assert.Equal(t, [3]game.BayStatus{0, 0, 0}, web.arena.RedRealtimeScore.CurrentScore.RocketFarLeftBays)
|
||||
assert.Equal(t, [3]game.BayStatus{0, 0, 0}, web.arena.RedRealtimeScore.CurrentScore.RocketFarRightBays)
|
||||
// TODO(pat): Update for 2020.
|
||||
/*
|
||||
// Send a some pre-match scoring commands.
|
||||
redWs.Write("1", nil)
|
||||
blueWs.Write("2", nil)
|
||||
blueWs.Write("2", nil)
|
||||
blueWs.Write("2", nil)
|
||||
blueWs.Write("2", nil)
|
||||
for i := 0; i < 5; i++ {
|
||||
readWebsocketType(t, redWs, "realtimeScore")
|
||||
readWebsocketType(t, blueWs, "realtimeScore")
|
||||
}
|
||||
assert.Equal(t, 1, web.arena.RedRealtimeScore.CurrentScore.RobotStartLevels[0])
|
||||
assert.Equal(t, 0, web.arena.BlueRealtimeScore.CurrentScore.RobotStartLevels[1])
|
||||
redWs.Write("e", nil)
|
||||
redWs.Write("i", nil)
|
||||
redWs.Write("i", nil)
|
||||
redWs.Write("v", nil)
|
||||
redWs.Write("q", nil)
|
||||
redWs.Write(",", nil)
|
||||
for i := 0; i < 3; i++ {
|
||||
readWebsocketType(t, redWs, "realtimeScore")
|
||||
readWebsocketType(t, blueWs, "realtimeScore")
|
||||
}
|
||||
assert.Equal(t, [8]game.BayStatus{1, 0, 0, 0, 0, 0, 0, 3},
|
||||
web.arena.RedRealtimeScore.CurrentScore.CargoBaysPreMatch)
|
||||
assert.Equal(t, [8]game.BayStatus{1, 0, 0, 0, 0, 0, 0, 3}, web.arena.RedRealtimeScore.CurrentScore.CargoBays)
|
||||
assert.Equal(t, [3]game.BayStatus{0, 0, 0}, web.arena.RedRealtimeScore.CurrentScore.RocketNearLeftBays)
|
||||
assert.Equal(t, [3]game.BayStatus{0, 0, 0}, web.arena.RedRealtimeScore.CurrentScore.RocketNearRightBays)
|
||||
assert.Equal(t, [3]game.BayStatus{0, 0, 0}, web.arena.RedRealtimeScore.CurrentScore.RocketFarLeftBays)
|
||||
assert.Equal(t, [3]game.BayStatus{0, 0, 0}, web.arena.RedRealtimeScore.CurrentScore.RocketFarRightBays)
|
||||
|
||||
// Send some in-match scoring commands.
|
||||
web.arena.MatchState = field.AutoPeriod
|
||||
redWs.Write("e", nil)
|
||||
redWs.Write("i", nil)
|
||||
redWs.Write("k", nil)
|
||||
redWs.Write("4", nil)
|
||||
blueWs.Write("9", nil)
|
||||
for i := 0; i < 5; i++ {
|
||||
readWebsocketType(t, redWs, "realtimeScore")
|
||||
readWebsocketType(t, blueWs, "realtimeScore")
|
||||
}
|
||||
assert.Equal(t, [8]game.BayStatus{1, 0, 0, 0, 0, 0, 0, 3},
|
||||
web.arena.RedRealtimeScore.CurrentScore.CargoBaysPreMatch)
|
||||
assert.Equal(t, [8]game.BayStatus{2, 0, 0, 0, 0, 0, 0, 2}, web.arena.RedRealtimeScore.CurrentScore.CargoBays)
|
||||
assert.Equal(t, [3]game.BayStatus{0, 1, 0}, web.arena.RedRealtimeScore.CurrentScore.RocketFarRightBays)
|
||||
assert.True(t, web.arena.RedRealtimeScore.CurrentScore.SandstormBonuses[0])
|
||||
assert.Equal(t, 1, web.arena.BlueRealtimeScore.CurrentScore.RobotEndLevels[2])
|
||||
// Send some in-match scoring commands.
|
||||
web.arena.MatchState = field.AutoPeriod
|
||||
redWs.Write("e", nil)
|
||||
redWs.Write("i", nil)
|
||||
redWs.Write("k", nil)
|
||||
redWs.Write("4", nil)
|
||||
blueWs.Write("9", nil)
|
||||
for i := 0; i < 5; i++ {
|
||||
readWebsocketType(t, redWs, "realtimeScore")
|
||||
readWebsocketType(t, blueWs, "realtimeScore")
|
||||
}
|
||||
assert.Equal(t, [8]game.BayStatus{1, 0, 0, 0, 0, 0, 0, 3},
|
||||
web.arena.RedRealtimeScore.CurrentScore.CargoBaysPreMatch)
|
||||
assert.Equal(t, [8]game.BayStatus{2, 0, 0, 0, 0, 0, 0, 2}, web.arena.RedRealtimeScore.CurrentScore.CargoBays)
|
||||
assert.Equal(t, [3]game.BayStatus{0, 1, 0}, web.arena.RedRealtimeScore.CurrentScore.RocketFarRightBays)
|
||||
assert.True(t, web.arena.RedRealtimeScore.CurrentScore.SandstormBonuses[0])
|
||||
assert.Equal(t, 1, web.arena.BlueRealtimeScore.CurrentScore.RobotEndLevels[2])
|
||||
*/
|
||||
|
||||
// Test committing logic.
|
||||
redWs.Write("commitMatch", nil)
|
||||
|
||||
Reference in New Issue
Block a user