From f075b7bb8da9ec555d64338ff3669e25ab3cfb49 Mon Sep 17 00:00:00 2001 From: Ken Schenke Date: Tue, 14 Apr 2020 19:38:14 -0500 Subject: [PATCH] Remove game-specific scoring --- db/migrations/20140520222523_CreateTeams.sql | 1 - .../20140524160241_CreateEventSettings.sql | 5 +- .../20140526180544_CreateMatchResults.sql | 4 +- field/arena.go | 152 +---------- field/arena_notifiers.go | 52 +--- field/realtime_score.go | 20 -- field/scoring_panel_registry.go | 78 ------ field/scoring_panel_registry_test.go | 51 ---- game/control_panel.go | 166 ------------ game/control_panel_test.go | 156 ----------- game/foul.go | 29 --- game/match_timing.go | 12 - game/match_timing_test.go | 18 -- game/power_port.go | 54 ---- game/power_port_test.go | 70 ----- game/ranking_fields.go | 17 +- game/ranking_fields_test.go | 46 ++-- game/rule.go | 69 ----- game/rule_test.go | 24 -- game/score.go | 206 ++------------- game/score_test.go | 246 +----------------- game/test_helpers.go | 39 +-- model/event_settings.go | 6 - model/event_settings_test.go | 3 +- model/match_result.go | 43 +-- model/match_result_test.go | 2 - model/team.go | 1 - model/test_helpers.go | 2 - partner/tba.go | 138 +--------- plc/armorblock_string.go | 8 +- plc/coil_string.go | 17 +- plc/input_string.go | 10 +- plc/plc.go | 95 ------- plc/plc_test.go | 16 +- plc/register_string.go | 26 +- static/js/match_play.js | 63 ++++- static/js/match_review.js | 108 +------- templates/base.html | 10 - templates/edit_match_result.html | 185 +------------ templates/match_play.html | 42 ++- templates/rankings.csv | 4 +- templates/setup_settings.html | 18 -- tournament/qualification_rankings.go | 68 +---- tournament/qualification_rankings_test.go | 59 ++--- web/alliance_selection.go | 7 - web/alliance_selection_test.go | 4 +- web/api.go | 4 +- web/match_play.go | 31 +-- web/match_play_test.go | 71 +---- web/match_review.go | 17 +- web/match_review_test.go | 20 +- web/referee_panel.go | 225 ---------------- web/referee_panel_test.go | 119 --------- web/reports.go | 2 - web/reports_test.go | 2 +- web/scoring_panel.go | 237 ----------------- web/scoring_panel_test.go | 117 --------- web/setup_settings.go | 3 - web/web.go | 4 - 59 files changed, 298 insertions(+), 3004 deletions(-) mode change 100644 => 100755 db/migrations/20140524160241_CreateEventSettings.sql mode change 100644 => 100755 field/arena.go mode change 100644 => 100755 field/arena_notifiers.go delete mode 100644 field/realtime_score.go delete mode 100644 field/scoring_panel_registry.go delete mode 100644 field/scoring_panel_registry_test.go delete mode 100644 game/control_panel.go delete mode 100644 game/control_panel_test.go delete mode 100644 game/foul.go delete mode 100644 game/match_timing_test.go delete mode 100644 game/power_port.go delete mode 100644 game/power_port_test.go mode change 100644 => 100755 game/ranking_fields.go delete mode 100644 game/rule.go delete mode 100644 game/rule_test.go mode change 100644 => 100755 game/score.go mode change 100644 => 100755 game/test_helpers.go mode change 100644 => 100755 model/event_settings.go mode change 100644 => 100755 model/match_result.go mode change 100644 => 100755 model/test_helpers.go mode change 100644 => 100755 partner/tba.go mode change 100644 => 100755 static/js/match_play.js mode change 100644 => 100755 templates/base.html mode change 100644 => 100755 templates/match_play.html mode change 100644 => 100755 templates/setup_settings.html mode change 100644 => 100755 tournament/qualification_rankings.go mode change 100644 => 100755 web/alliance_selection.go mode change 100644 => 100755 web/api.go mode change 100644 => 100755 web/match_play.go mode change 100644 => 100755 web/match_review.go delete mode 100644 web/referee_panel.go delete mode 100644 web/referee_panel_test.go mode change 100644 => 100755 web/reports.go delete mode 100644 web/scoring_panel.go delete mode 100644 web/scoring_panel_test.go mode change 100644 => 100755 web/setup_settings.go mode change 100644 => 100755 web/web.go diff --git a/db/migrations/20140520222523_CreateTeams.sql b/db/migrations/20140520222523_CreateTeams.sql index 29f312f..f9cff2a 100644 --- a/db/migrations/20140520222523_CreateTeams.sql +++ b/db/migrations/20140520222523_CreateTeams.sql @@ -10,7 +10,6 @@ CREATE TABLE teams ( robotname VARCHAR(255), accomplishments VARCHAR(1000), wpakey VARCHAR(16), - yellowcard bool, hasconnected bool, ftanotes VARCHAR(1000) ); diff --git a/db/migrations/20140524160241_CreateEventSettings.sql b/db/migrations/20140524160241_CreateEventSettings.sql old mode 100644 new mode 100755 index 290b6ab..806f0e5 --- a/db/migrations/20140524160241_CreateEventSettings.sql +++ b/db/migrations/20140524160241_CreateEventSettings.sql @@ -30,10 +30,7 @@ CREATE TABLE event_settings ( autodurationsec int, pausedurationsec int, teleopdurationsec int, - warningremainingdurationsec int, - stage1capacity int, - stage2capacity int, - stage3capacity int + warningremainingdurationsec int ); -- +goose Down diff --git a/db/migrations/20140526180544_CreateMatchResults.sql b/db/migrations/20140526180544_CreateMatchResults.sql index 0779520..886dcd5 100644 --- a/db/migrations/20140526180544_CreateMatchResults.sql +++ b/db/migrations/20140526180544_CreateMatchResults.sql @@ -5,9 +5,7 @@ CREATE TABLE match_results ( playnumber int, matchtype VARCHAR(16), redscorejson text, - bluescorejson text, - redcardsjson text, - bluecardsjson text + bluescorejson text ); CREATE UNIQUE INDEX matchid_playnumber ON match_results(matchid, playnumber); diff --git a/field/arena.go b/field/arena.go old mode 100644 new mode 100755 index 1cfbf48..d319379 --- a/field/arena.go +++ b/field/arena.go @@ -52,15 +52,14 @@ type Arena struct { TbaClient *partner.TbaClient AllianceStations map[string]*AllianceStation Displays map[string]*Display - ScoringPanelRegistry ArenaNotifiers MatchState lastMatchState MatchState CurrentMatch *model.Match MatchStartTime time.Time LastMatchTimeSec float64 - RedRealtimeScore *RealtimeScore - BlueRealtimeScore *RealtimeScore + RedScore *game.Score + BlueScore *game.Score lastDsPacketTime time.Time lastPeriodicTaskTime time.Time EventStatus EventStatus @@ -113,8 +112,6 @@ func NewArena(dbPath string) (*Arena, error) { arena.Displays = make(map[string]*Display) - arena.ScoringPanelRegistry.initialize() - // Load empty match as current. arena.MatchState = PreMatch arena.LoadTestMatch() @@ -164,10 +161,6 @@ func (arena *Arena) LoadSettings() error { game.UpdateMatchSounds() arena.MatchTimingNotifier.Notify() - game.StageCapacities[game.Stage1] = settings.Stage1Capacity - game.StageCapacities[game.Stage2] = settings.Stage2Capacity - game.StageCapacities[game.Stage3] = settings.Stage3Capacity - return nil } @@ -207,13 +200,12 @@ func (arena *Arena) LoadMatch(match *model.Match) error { arena.AllianceStations["R3"].Team, arena.AllianceStations["B1"].Team, arena.AllianceStations["B2"].Team, arena.AllianceStations["B3"].Team}) - // Reset the arena state and realtime scores. + // Reset the arena state and game scores. arena.soundsPlayed = make(map[*game.MatchSound]struct{}) - arena.RedRealtimeScore = NewRealtimeScore() - arena.BlueRealtimeScore = NewRealtimeScore() + arena.RedScore = new(game.Score) + arena.BlueScore = new(game.Score) arena.FieldVolunteers = false arena.FieldReset = false - arena.ScoringPanelRegistry.resetScoreCommitted() // Notify any listeners about the new match. arena.MatchLoadNotifier.Notify() @@ -522,14 +514,12 @@ func (arena *Arena) Run() { // Calculates the red alliance score summary for the given realtime snapshot. func (arena *Arena) RedScoreSummary() *game.ScoreSummary { - return arena.RedRealtimeScore.CurrentScore.Summarize(arena.BlueRealtimeScore.CurrentScore.Fouls, - arena.MatchState >= TeleopPeriod) + return arena.RedScore.Summarize() } // Calculates the blue alliance score summary for the given realtime snapshot. func (arena *Arena) BlueScoreSummary() *game.ScoreSummary { - return arena.BlueRealtimeScore.CurrentScore.Summarize(arena.RedRealtimeScore.CurrentScore.Fouls, - arena.MatchState >= TeleopPeriod) + return arena.BlueScore.Summarize() } // Loads a team into an alliance station, cleaning up the previous team there if there is one. @@ -704,23 +694,6 @@ func (arena *Arena) sendDsPacket(auto bool, enabled bool) { arena.lastDsPacketTime = time.Now() } -// Sends a game data packet encoded with the given Control Panel target color to the given stations. -func (arena *Arena) sendGameDataPacket(color game.ControlPanelColor, stations ...string) { - gameData := game.GetGameDataForColor(color) - log.Printf("Sending game data packet '%s' to stations %v", gameData, stations) - for _, station := range stations { - if allianceStation, ok := arena.AllianceStations[station]; ok { - dsConn := allianceStation.DsConn - if dsConn != nil { - err := dsConn.sendGameDataPacket(gameData) - if err != nil { - log.Printf("Error sending game data packet to Team %d: %v", dsConn.TeamId, err) - } - } - } - } -} - // Returns the alliance station identifier for the given team, or the empty string if the team is not present // in the current match. func (arena *Arena) getAssignedAllianceStation(teamId int) string { @@ -759,79 +732,10 @@ func (arena *Arena) handlePlcInput() { // Don't do anything if we're outside the match, otherwise we may overwrite manual edits. return } - - redScore := &arena.RedRealtimeScore.CurrentScore - oldRedScore := *redScore - blueScore := &arena.BlueRealtimeScore.CurrentScore - oldBlueScore := *blueScore - matchStartTime := arena.MatchStartTime - currentTime := time.Now() - teleopStarted := arena.MatchState >= TeleopPeriod - - if arena.Plc.IsEnabled() { - // Handle power ports. - redPortCells, bluePortCells := arena.Plc.GetPowerPorts() - redPowerPort := &arena.RedRealtimeScore.powerPort - redPowerPort.UpdateState(redPortCells, redScore.CellCountingStage(teleopStarted), matchStartTime, currentTime) - redScore.AutoCellsBottom = redPowerPort.AutoCellsBottom - redScore.AutoCellsOuter = redPowerPort.AutoCellsOuter - redScore.AutoCellsInner = redPowerPort.AutoCellsInner - redScore.TeleopCellsBottom = redPowerPort.TeleopCellsBottom - redScore.TeleopCellsOuter = redPowerPort.TeleopCellsOuter - redScore.TeleopCellsInner = redPowerPort.TeleopCellsInner - bluePowerPort := &arena.BlueRealtimeScore.powerPort - bluePowerPort.UpdateState(bluePortCells, blueScore.CellCountingStage(teleopStarted), matchStartTime, - currentTime) - blueScore.AutoCellsBottom = bluePowerPort.AutoCellsBottom - blueScore.AutoCellsOuter = bluePowerPort.AutoCellsOuter - blueScore.AutoCellsInner = bluePowerPort.AutoCellsInner - blueScore.TeleopCellsBottom = bluePowerPort.TeleopCellsBottom - blueScore.TeleopCellsOuter = bluePowerPort.TeleopCellsOuter - blueScore.TeleopCellsInner = bluePowerPort.TeleopCellsInner - - // Handle control panel. - redColor, redSegmentCount, blueColor, blueSegmentCount := arena.Plc.GetControlPanels() - redControlPanel := &arena.RedRealtimeScore.ControlPanel - redControlPanel.CurrentColor = redColor - redControlPanel.UpdateState(redSegmentCount, redScore.StageAtCapacity(game.Stage2, teleopStarted), - redScore.StageAtCapacity(game.Stage3, teleopStarted), currentTime) - redScore.ControlPanelStatus = redControlPanel.ControlPanelStatus - blueControlPanel := &arena.BlueRealtimeScore.ControlPanel - blueControlPanel.CurrentColor = blueColor - blueControlPanel.UpdateState(blueSegmentCount, blueScore.StageAtCapacity(game.Stage2, teleopStarted), - blueScore.StageAtCapacity(game.Stage3, teleopStarted), currentTime) - blueScore.ControlPanelStatus = blueControlPanel.ControlPanelStatus - - // Handle shield generator rungs. - if game.ShouldAssessRung(matchStartTime, currentTime) { - redScore.RungIsLevel, blueScore.RungIsLevel = arena.Plc.GetRungs() - } - } - - // Check if either alliance has reached Stage 3 capacity. - if redScore.StageAtCapacity(game.Stage3, arena.MatchState >= TeleopPeriod) && - redScore.PositionControlTargetColor == game.ColorUnknown || - blueScore.StageAtCapacity(game.Stage3, arena.MatchState >= TeleopPeriod) && - blueScore.PositionControlTargetColor == game.ColorUnknown { - // Determine the position control target colors and send packets to inform the driver stations. - redScore.PositionControlTargetColor = arena.RedRealtimeScore.ControlPanel.GetPositionControlTargetColor() - blueScore.PositionControlTargetColor = arena.BlueRealtimeScore.ControlPanel.GetPositionControlTargetColor() - arena.sendGameDataPacket(redScore.PositionControlTargetColor, "R1", "R2", "R3") - arena.sendGameDataPacket(blueScore.PositionControlTargetColor, "B1", "B2", "B3") - } - - if !oldRedScore.Equals(redScore) || !oldBlueScore.Equals(blueScore) { - arena.RealtimeScoreNotifier.Notify() - } } // Updates the PLC's coils based on its inputs and the current scoring state. func (arena *Arena) handlePlcOutput() { - matchStartTime := arena.MatchStartTime - currentTime := time.Now() - redScore := &arena.RedRealtimeScore.CurrentScore - blueScore := &arena.BlueRealtimeScore.CurrentScore - switch arena.MatchState { case PreMatch: if arena.lastMatchState != PreMatch { @@ -857,51 +761,18 @@ func (arena *Arena) handlePlcOutput() { if arena.FieldReset { arena.Plc.SetFieldResetLight(true) } - scoreReady := arena.RedRealtimeScore.FoulsCommitted && arena.BlueRealtimeScore.FoulsCommitted && - arena.alliancePostMatchScoreReady("red") && arena.alliancePostMatchScoreReady("blue") - arena.Plc.SetStackLights(false, false, !scoreReady, false) + arena.Plc.SetStackLights(false, false, false, false) if arena.lastMatchState != PostMatch { go func() { - time.Sleep(time.Second * game.PowerPortTeleopGracePeriodSec) - arena.Plc.SetPowerPortMotors(false) + time.Sleep(time.Second) }() } - arena.Plc.SetStageActivatedLights([3]bool{false, false, false}, [3]bool{false, false, false}) - arena.Plc.SetControlPanelLights(false, false) case AutoPeriod: - arena.Plc.SetPowerPortMotors(true) fallthrough case PausePeriod: fallthrough case TeleopPeriod: - arena.Plc.SetStageActivatedLights(arena.RedScoreSummary().StagesActivated, - arena.BlueScoreSummary().StagesActivated) - - controlPanelLightState := func(state game.ControlPanelLightState) bool { - switch state { - case game.ControlPanelLightOn: - return true - case game.ControlPanelLightFlashing: - return arena.Plc.GetCycleState(2, 0, 2) - default: - return false - } - } - arena.Plc.SetControlPanelLights( - controlPanelLightState(arena.RedRealtimeScore.ControlPanel.ControlPanelLightState), - controlPanelLightState(arena.BlueRealtimeScore.ControlPanel.ControlPanelLightState)) - - // If the PLC reports a ball jam, blink the orange light and the power port color. - redJam, blueJam := arena.Plc.GetPowerPortJams() - blink := arena.Plc.GetCycleState(2, 0, 2) - arena.Plc.SetStackLights(redJam && blink, blueJam && blink, (redJam || blueJam) && !blink, true) - } - - if game.ShouldAssessRung(matchStartTime, currentTime) { - arena.Plc.SetShieldGeneratorLights(redScore.RungIsLevel, blueScore.RungIsLevel) - } else { - arena.Plc.SetShieldGeneratorLights(false, false) } } @@ -950,11 +821,6 @@ func (arena *Arena) playSound(name string) { } } -func (arena *Arena) alliancePostMatchScoreReady(alliance string) bool { - numPanels := arena.ScoringPanelRegistry.GetNumPanels(alliance) - return numPanels > 0 && arena.ScoringPanelRegistry.GetNumScoreCommitted(alliance) >= numPanels -} - // Performs any actions that need to run at the interval specified by periodicTaskPeriodSec. func (arena *Arena) runPeriodicTasks() { arena.updateEarlyLateMessage() diff --git a/field/arena_notifiers.go b/field/arena_notifiers.go old mode 100644 new mode 100755 index d586d20..ada58a6 --- a/field/arena_notifiers.go +++ b/field/arena_notifiers.go @@ -29,7 +29,6 @@ type ArenaNotifiers struct { RealtimeScoreNotifier *websocket.Notifier ReloadDisplaysNotifier *websocket.Notifier ScorePostedNotifier *websocket.Notifier - ScoringStatusNotifier *websocket.Notifier } type MatchTimeMessage struct { @@ -40,7 +39,6 @@ type MatchTimeMessage struct { type audienceAllianceScoreFields struct { Score *game.Score ScoreSummary *game.ScoreSummary - ControlPanel *game.ControlPanel } // Instantiates notifiers and configures their message producing methods. @@ -62,7 +60,6 @@ func (arena *Arena) configureNotifiers() { arena.RealtimeScoreNotifier = websocket.NewNotifier("realtimeScore", arena.generateRealtimeScoreMessage) arena.ReloadDisplaysNotifier = websocket.NewNotifier("reload", nil) arena.ScorePostedNotifier = websocket.NewNotifier("scorePosted", arena.generateScorePostedMessage) - arena.ScoringStatusNotifier = websocket.NewNotifier("scoringStatus", arena.generateScoringStatusMessage) } func (arena *Arena) generateAllianceSelectionMessage() interface{} { @@ -160,8 +157,8 @@ func (arena *Arena) generateRealtimeScoreMessage() interface{} { Blue *audienceAllianceScoreFields MatchState }{} - fields.Red = getAudienceAllianceScoreFields(arena.RedRealtimeScore, arena.RedScoreSummary()) - fields.Blue = getAudienceAllianceScoreFields(arena.BlueRealtimeScore, arena.BlueScoreSummary()) + fields.Red = getAudienceAllianceScoreFields(arena.RedScore, arena.RedScoreSummary()) + fields.Blue = getAudienceAllianceScoreFields(arena.BlueScore, arena.BlueScoreSummary()) fields.MatchState = arena.MatchState return &fields } @@ -208,53 +205,18 @@ func (arena *Arena) generateScorePostedMessage() interface{} { RedScoreSummary *game.ScoreSummary BlueScoreSummary *game.ScoreSummary Rankings map[int]game.Ranking - RedFouls []game.Foul - BlueFouls []game.Foul - RulesViolated map[int]*game.Rule - RedCards map[string]string - BlueCards map[string]string SeriesStatus string SeriesLeader string - }{arena.SavedMatch.CapitalizedType(), arena.SavedMatch, arena.SavedMatchResult.RedScoreSummary(true), - arena.SavedMatchResult.BlueScoreSummary(true), rankings, arena.SavedMatchResult.RedScore.Fouls, - arena.SavedMatchResult.BlueScore.Fouls, - getRulesViolated(arena.SavedMatchResult.RedScore.Fouls, arena.SavedMatchResult.BlueScore.Fouls), - arena.SavedMatchResult.RedCards, arena.SavedMatchResult.BlueCards, seriesStatus, seriesLeader} -} - -func (arena *Arena) generateScoringStatusMessage() interface{} { - return &struct { - RefereeScoreReady bool - RedScoreReady bool - BlueScoreReady bool - NumRedScoringPanels int - NumRedScoringPanelsReady int - NumBlueScoringPanels int - NumBlueScoringPanelsReady int - }{arena.RedRealtimeScore.FoulsCommitted && arena.BlueRealtimeScore.FoulsCommitted, - arena.alliancePostMatchScoreReady("red"), arena.alliancePostMatchScoreReady("blue"), - arena.ScoringPanelRegistry.GetNumPanels("red"), arena.ScoringPanelRegistry.GetNumScoreCommitted("red"), - arena.ScoringPanelRegistry.GetNumPanels("blue"), arena.ScoringPanelRegistry.GetNumScoreCommitted("blue")} + }{arena.SavedMatch.CapitalizedType(), arena.SavedMatch, arena.SavedMatchResult.RedScoreSummary(), + arena.SavedMatchResult.BlueScoreSummary(), rankings, + seriesStatus, seriesLeader} } // Constructs the data object for one alliance sent to the audience display for the realtime scoring overlay. -func getAudienceAllianceScoreFields(allianceScore *RealtimeScore, +func getAudienceAllianceScoreFields(allianceScore *game.Score, allianceScoreSummary *game.ScoreSummary) *audienceAllianceScoreFields { fields := new(audienceAllianceScoreFields) - fields.Score = &allianceScore.CurrentScore + fields.Score = allianceScore fields.ScoreSummary = allianceScoreSummary - fields.ControlPanel = &allianceScore.ControlPanel return fields } - -// Produce a map of rules that were violated by either alliance so that they are available to the announcer. -func getRulesViolated(redFouls, blueFouls []game.Foul) map[int]*game.Rule { - rules := make(map[int]*game.Rule) - for _, foul := range redFouls { - rules[foul.RuleId] = game.GetRuleById(foul.RuleId) - } - for _, foul := range blueFouls { - rules[foul.RuleId] = game.GetRuleById(foul.RuleId) - } - return rules -} diff --git a/field/realtime_score.go b/field/realtime_score.go deleted file mode 100644 index 6c294df..0000000 --- a/field/realtime_score.go +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2017 Team 254. All Rights Reserved. -// Author: pat@patfairbank.com (Patrick Fairbank) -// -// Model representing the current state of the score during a match. - -package field - -import "github.com/Team254/cheesy-arena/game" - -type RealtimeScore struct { - CurrentScore game.Score - Cards map[string]string - FoulsCommitted bool - powerPort game.PowerPort - ControlPanel game.ControlPanel -} - -func NewRealtimeScore() *RealtimeScore { - return &RealtimeScore{Cards: make(map[string]string)} -} diff --git a/field/scoring_panel_registry.go b/field/scoring_panel_registry.go deleted file mode 100644 index 7ae563e..0000000 --- a/field/scoring_panel_registry.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2019 Team 254. All Rights Reserved. -// Author: pat@patfairbank.com (Patrick Fairbank) -// -// Model representing and methods for tracking the state of a realtime scoring panel. - -package field - -import ( - "github.com/Team254/cheesy-arena/websocket" - "sync" -) - -type ScoringPanelRegistry struct { - scoringPanels map[string]map[*websocket.Websocket]bool // The score committed state for each panel. - mutex sync.Mutex -} - -func (registry *ScoringPanelRegistry) initialize() { - registry.scoringPanels = map[string]map[*websocket.Websocket]bool{"red": {}, "blue": {}} -} - -// Resets the score committed state for each registered panel to false. -func (registry *ScoringPanelRegistry) resetScoreCommitted() { - registry.mutex.Lock() - defer registry.mutex.Unlock() - - for _, alliancePanels := range registry.scoringPanels { - for key := range alliancePanels { - alliancePanels[key] = false - } - } -} - -// Returns the number of registered panels for the given alliance. -func (registry *ScoringPanelRegistry) GetNumPanels(alliance string) int { - registry.mutex.Lock() - defer registry.mutex.Unlock() - - return len(registry.scoringPanels[alliance]) -} - -// Returns the number of registered panels whose score is committed for the given alliance. -func (registry *ScoringPanelRegistry) GetNumScoreCommitted(alliance string) int { - registry.mutex.Lock() - defer registry.mutex.Unlock() - - numCommitted := 0 - for _, panel := range registry.scoringPanels[alliance] { - if panel { - numCommitted++ - } - } - return numCommitted -} - -// Adds a panel to the registry, referenced by its websocket pointer. -func (registry *ScoringPanelRegistry) RegisterPanel(alliance string, ws *websocket.Websocket) { - registry.mutex.Lock() - defer registry.mutex.Unlock() - - registry.scoringPanels[alliance][ws] = false -} - -// Sets the score committed state to true for the given panel, referenced by its websocket pointer. -func (registry *ScoringPanelRegistry) SetScoreCommitted(alliance string, ws *websocket.Websocket) { - registry.mutex.Lock() - defer registry.mutex.Unlock() - - registry.scoringPanels[alliance][ws] = true -} - -// Removes a panel from the registry, referenced by its websocket pointer. -func (registry *ScoringPanelRegistry) UnregisterPanel(alliance string, ws *websocket.Websocket) { - registry.mutex.Lock() - defer registry.mutex.Unlock() - - delete(registry.scoringPanels[alliance], ws) -} diff --git a/field/scoring_panel_registry_test.go b/field/scoring_panel_registry_test.go deleted file mode 100644 index bbc37cb..0000000 --- a/field/scoring_panel_registry_test.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2019 Team 254. All Rights Reserved. -// Author: pat@patfairbank.com (Patrick Fairbank) - -package field - -import ( - "github.com/Team254/cheesy-arena/websocket" - "github.com/stretchr/testify/assert" - "testing" -) - -func TestScoringPanelRegistry(t *testing.T) { - var registry ScoringPanelRegistry - registry.initialize() - assert.Equal(t, 0, registry.GetNumPanels("red")) - assert.Equal(t, 0, registry.GetNumScoreCommitted("red")) - assert.Equal(t, 0, registry.GetNumPanels("blue")) - assert.Equal(t, 0, registry.GetNumScoreCommitted("blue")) - - ws1 := new(websocket.Websocket) - ws2 := new(websocket.Websocket) - ws3 := new(websocket.Websocket) - registry.RegisterPanel("red", ws1) - registry.RegisterPanel("blue", ws2) - registry.RegisterPanel("red", ws3) - assert.Equal(t, 2, registry.GetNumPanels("red")) - assert.Equal(t, 0, registry.GetNumScoreCommitted("red")) - assert.Equal(t, 1, registry.GetNumPanels("blue")) - assert.Equal(t, 0, registry.GetNumScoreCommitted("blue")) - - registry.SetScoreCommitted("red", ws3) - registry.SetScoreCommitted("blue", ws2) - registry.SetScoreCommitted("blue", ws2) - assert.Equal(t, 2, registry.GetNumPanels("red")) - assert.Equal(t, 1, registry.GetNumScoreCommitted("red")) - assert.Equal(t, 1, registry.GetNumPanels("blue")) - assert.Equal(t, 1, registry.GetNumScoreCommitted("blue")) - - registry.UnregisterPanel("red", ws1) - registry.UnregisterPanel("blue", ws2) - assert.Equal(t, 1, registry.GetNumPanels("red")) - assert.Equal(t, 1, registry.GetNumScoreCommitted("red")) - assert.Equal(t, 0, registry.GetNumPanels("blue")) - assert.Equal(t, 0, registry.GetNumScoreCommitted("blue")) - - registry.resetScoreCommitted() - assert.Equal(t, 1, registry.GetNumPanels("red")) - assert.Equal(t, 0, registry.GetNumScoreCommitted("red")) - assert.Equal(t, 0, registry.GetNumPanels("blue")) - assert.Equal(t, 0, registry.GetNumScoreCommitted("blue")) -} diff --git a/game/control_panel.go b/game/control_panel.go deleted file mode 100644 index 66c1364..0000000 --- a/game/control_panel.go +++ /dev/null @@ -1,166 +0,0 @@ -// Copyright 2020 Team 254. All Rights Reserved. -// Author: pat@patfairbank.com (Patrick Fairbank) -// -// Represents the state of an alliance Control Panel in the 2020 game. - -package game - -import ( - "math" - "math/rand" - "time" -) - -type ControlPanel struct { - CurrentColor ControlPanelColor - ControlPanelStatus - ControlPanelLightState - rotationStarted bool - rotationStartSegmentCount int - lastSegmentCountDiff int - rotationStopTime time.Time - positionTargetColor ControlPanelColor - lastPositionCorrect bool - positionStopTime time.Time -} - -type ControlPanelColor int - -// This ordering matches the values in the official FRC PLC code: 0:UnknownError, 1:Red, 2:Blue, 3:Green, 4:Yellow -const ( - ColorUnknown ControlPanelColor = iota - ColorRed - ColorBlue - ColorGreen - ColorYellow -) - -type ControlPanelStatus int - -const ( - ControlPanelNone ControlPanelStatus = iota - ControlPanelRotation - ControlPanelPosition -) - -type ControlPanelLightState int - -const ( - ControlPanelLightOff ControlPanelLightState = iota - ControlPanelLightOn - ControlPanelLightFlashing -) - -const ( - rotationControlMinSegments = 24 - rotationControlMaxSegments = 40 - rotationControlStopDurationSec = 2 - positionControlStopMinDurationSec = 3 - positionControlStopMaxDurationSec = 5 -) - -// Updates the internal state of the control panel given the current state of the hardware counts and the rest of the -// score. -func (controlPanel *ControlPanel) UpdateState(segmentCount int, stage2AtCapacity, stage3AtCapacity bool, - currentTime time.Time) { - if !stage2AtCapacity { - controlPanel.ControlPanelStatus = ControlPanelNone - controlPanel.ControlPanelLightState = ControlPanelLightOff - } else if controlPanel.ControlPanelStatus == ControlPanelNone { - controlPanel.assessRotationControl(segmentCount, currentTime) - } else if controlPanel.ControlPanelStatus == ControlPanelRotation && stage3AtCapacity { - controlPanel.assessPositionControl(currentTime) - } else { - controlPanel.ControlPanelLightState = ControlPanelLightOff - } -} - -// Returns the target color for position control, assigning it randomly if it is not yet designated. -func (controlPanel *ControlPanel) GetPositionControlTargetColor() ControlPanelColor { - if controlPanel.positionTargetColor == ColorUnknown { - if controlPanel.CurrentColor == ColorUnknown { - // If the sensor or manual scorekeeping did not detect/set the current color, pick one of the four at - // random. - controlPanel.positionTargetColor = ControlPanelColor(rand.Intn(4) + 1) - } else { - // Randomly pick one of the non-current colors. - newColor := int(controlPanel.CurrentColor) + rand.Intn(3) + 1 - if newColor > 4 { - newColor -= 4 - } - controlPanel.positionTargetColor = ControlPanelColor(newColor) - } - } - return controlPanel.positionTargetColor -} - -// Returns the string that is to be sent to the driver station for the given color. -func GetGameDataForColor(color ControlPanelColor) string { - switch color { - case ColorRed: - return "R" - case ColorBlue: - return "B" - case ColorGreen: - return "G" - case ColorYellow: - return "Y" - } - return "" -} - -// Updates the state of the control panel while rotation control is in the process of being performed. -func (controlPanel *ControlPanel) assessRotationControl(segmentCount int, currentTime time.Time) { - if !controlPanel.rotationStarted { - controlPanel.rotationStarted = true - controlPanel.rotationStartSegmentCount = segmentCount - } - - segmentCountDiff := int(math.Abs(float64(segmentCount - controlPanel.rotationStartSegmentCount))) - if segmentCountDiff < rotationControlMinSegments { - // The control panel still needs to be rotated more. - controlPanel.ControlPanelLightState = ControlPanelLightOn - } else if segmentCountDiff < rotationControlMaxSegments { - // The control panel has been rotated the correct amount and needs to stop on a single color. - if segmentCountDiff != controlPanel.lastSegmentCountDiff { - // The control panel is still moving; reset the timer. - controlPanel.rotationStopTime = currentTime - controlPanel.ControlPanelLightState = ControlPanelLightFlashing - } else if currentTime.Sub(controlPanel.rotationStopTime) < rotationControlStopDurationSec*time.Second { - controlPanel.ControlPanelLightState = ControlPanelLightFlashing - } else { - // The control panel has been stopped long enough; rotation control is complete. - controlPanel.ControlPanelStatus = ControlPanelRotation - controlPanel.ControlPanelLightState = ControlPanelLightOff - } - } else { - // The control panel has been rotated too much; reset the count. - controlPanel.rotationStartSegmentCount = segmentCount - controlPanel.ControlPanelLightState = ControlPanelLightOn - } - controlPanel.lastSegmentCountDiff = segmentCountDiff -} - -// Updates the state of the control panel while position control is in the process of being performed. -func (controlPanel *ControlPanel) assessPositionControl(currentTime time.Time) { - positionCorrect := controlPanel.CurrentColor == controlPanel.GetPositionControlTargetColor() && - controlPanel.CurrentColor != ColorUnknown - if positionCorrect && !controlPanel.lastPositionCorrect { - controlPanel.positionStopTime = currentTime - } - controlPanel.lastPositionCorrect = positionCorrect - - if !positionCorrect { - controlPanel.ControlPanelLightState = ControlPanelLightOn - } else if currentTime.Sub(controlPanel.positionStopTime) < positionControlStopMinDurationSec*time.Second { - // The control panel is on the target color but may still be moving. - controlPanel.ControlPanelLightState = ControlPanelLightOn - } else if currentTime.Sub(controlPanel.positionStopTime) < positionControlStopMaxDurationSec*time.Second { - // The control panel is stopped on the target color, but not long enough to count. - controlPanel.ControlPanelLightState = ControlPanelLightFlashing - } else { - // The target color has been present for long enough; position control is complete. - controlPanel.ControlPanelStatus = ControlPanelPosition - controlPanel.ControlPanelLightState = ControlPanelLightOff - } -} diff --git a/game/control_panel_test.go b/game/control_panel_test.go deleted file mode 100644 index 4c65614..0000000 --- a/game/control_panel_test.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2020 Team 254. All Rights Reserved. -// Author: pat@patfairbank.com (Patrick Fairbank) - -package game - -import ( - "github.com/stretchr/testify/assert" - "math/rand" - "testing" - "time" -) - -func TestControlPanelGetPositionControlTargetColor(t *testing.T) { - rand.Seed(0) - var controlPanel ControlPanel - - controlPanel.CurrentColor = ColorUnknown - results := getPositionTargetColorNTimes(&controlPanel, 10000) - assert.Equal(t, [5]int{0, 2543, 2527, 2510, 2420}, results) - - controlPanel.CurrentColor = ColorRed - results = getPositionTargetColorNTimes(&controlPanel, 10000) - assert.Equal(t, [5]int{0, 0, 3351, 3311, 3338}, results) - - controlPanel.CurrentColor = ColorBlue - results = getPositionTargetColorNTimes(&controlPanel, 10000) - assert.Equal(t, [5]int{0, 3335, 0, 3320, 3345}, results) - - controlPanel.CurrentColor = ColorGreen - results = getPositionTargetColorNTimes(&controlPanel, 10000) - assert.Equal(t, [5]int{0, 3328, 3296, 0, 3376}, results) - - controlPanel.CurrentColor = ColorYellow - results = getPositionTargetColorNTimes(&controlPanel, 10000) - assert.Equal(t, [5]int{0, 3303, 3388, 3309, 0}, results) -} - -func TestGetGameDataForColor(t *testing.T) { - assert.Equal(t, "", GetGameDataForColor(ColorUnknown)) - assert.Equal(t, "R", GetGameDataForColor(ColorRed)) - assert.Equal(t, "B", GetGameDataForColor(ColorBlue)) - assert.Equal(t, "G", GetGameDataForColor(ColorGreen)) - assert.Equal(t, "Y", GetGameDataForColor(ColorYellow)) - assert.Equal(t, "", GetGameDataForColor(-100)) -} - -func TestControlPanelUpdateState(t *testing.T) { - rand.Seed(0) - var controlPanel ControlPanel - controlPanel.ControlPanelStatus = ControlPanelRotation - currentTime := time.Now() - - // Check before Stage 2 capacity is reached. - controlPanel.UpdateState(0, false, false, currentTime) - assert.Equal(t, ControlPanelNone, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOff, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(30, false, false, currentTime) - assert.Equal(t, ControlPanelNone, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOff, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(50, false, false, currentTime) - assert.Equal(t, ControlPanelNone, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOff, controlPanel.ControlPanelLightState) - - // Check rotation control. - controlPanel.UpdateState(60, true, false, currentTime) - assert.Equal(t, ControlPanelNone, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOn, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(80, true, false, currentTime) - assert.Equal(t, ControlPanelNone, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOn, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(37, true, false, currentTime) - assert.Equal(t, ControlPanelNone, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOn, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(36, true, false, currentTime) - assert.Equal(t, ControlPanelNone, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightFlashing, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(40, true, false, currentTime) - assert.Equal(t, ControlPanelNone, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOn, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(35, true, false, currentTime) - assert.Equal(t, ControlPanelNone, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightFlashing, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(21, true, false, currentTime) - assert.Equal(t, ControlPanelNone, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightFlashing, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(20, true, false, currentTime) - assert.Equal(t, ControlPanelNone, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOn, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(44, true, false, currentTime) - assert.Equal(t, ControlPanelNone, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightFlashing, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(55, true, false, currentTime.Add(1*time.Millisecond)) - assert.Equal(t, ControlPanelNone, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightFlashing, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(55, true, false, currentTime.Add(2000*time.Millisecond)) - assert.Equal(t, ControlPanelNone, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightFlashing, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(55, true, false, currentTime.Add(2001*time.Millisecond)) - assert.Equal(t, ControlPanelRotation, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOff, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(-1000, true, false, currentTime.Add(3000*time.Millisecond)) - assert.Equal(t, ControlPanelRotation, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOff, controlPanel.ControlPanelLightState) - - // Check position control. - assert.Equal(t, ColorUnknown, controlPanel.positionTargetColor) - controlPanel.UpdateState(1000, true, true, currentTime.Add(5000*time.Millisecond)) - assert.Equal(t, ControlPanelRotation, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOn, controlPanel.ControlPanelLightState) - assert.Equal(t, ColorGreen, controlPanel.GetPositionControlTargetColor()) - controlPanel.CurrentColor = ColorBlue - controlPanel.UpdateState(1001, true, true, currentTime.Add(6000*time.Millisecond)) - assert.Equal(t, ControlPanelRotation, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOn, controlPanel.ControlPanelLightState) - controlPanel.CurrentColor = ColorGreen - controlPanel.UpdateState(1002, true, true, currentTime.Add(7000*time.Millisecond)) - assert.Equal(t, ControlPanelRotation, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOn, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(1002, true, true, currentTime.Add(9999*time.Millisecond)) - assert.Equal(t, ControlPanelRotation, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOn, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(1002, true, true, currentTime.Add(10000*time.Millisecond)) - assert.Equal(t, ControlPanelRotation, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightFlashing, controlPanel.ControlPanelLightState) - controlPanel.CurrentColor = ColorYellow - controlPanel.UpdateState(1003, true, true, currentTime.Add(11000*time.Millisecond)) - assert.Equal(t, ControlPanelRotation, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOn, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(1003, true, true, currentTime.Add(20000*time.Millisecond)) - assert.Equal(t, ControlPanelRotation, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOn, controlPanel.ControlPanelLightState) - controlPanel.CurrentColor = ColorGreen - controlPanel.UpdateState(1002, true, true, currentTime.Add(21000*time.Millisecond)) - assert.Equal(t, ControlPanelRotation, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOn, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(1002, true, true, currentTime.Add(25999*time.Millisecond)) - assert.Equal(t, ControlPanelRotation, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightFlashing, controlPanel.ControlPanelLightState) - controlPanel.UpdateState(1002, true, true, currentTime.Add(26000*time.Millisecond)) - assert.Equal(t, ControlPanelPosition, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOff, controlPanel.ControlPanelLightState) - controlPanel.CurrentColor = ColorRed - controlPanel.UpdateState(0, true, true, currentTime.Add(26001*time.Millisecond)) - assert.Equal(t, ControlPanelPosition, controlPanel.ControlPanelStatus) - assert.Equal(t, ControlPanelLightOff, controlPanel.ControlPanelLightState) -} - -// Invokes the method N times and returns a map of the counts for each result, for statistical testing. -func getPositionTargetColorNTimes(controlPanel *ControlPanel, n int) [5]int { - var results [5]int - for i := 0; i < n; i++ { - controlPanel.positionTargetColor = ColorUnknown - results[controlPanel.GetPositionControlTargetColor()]++ - } - return results -} diff --git a/game/foul.go b/game/foul.go deleted file mode 100644 index 10c9b9d..0000000 --- a/game/foul.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2017 Team 254. All Rights Reserved. -// Author: pat@patfairbank.com (Patrick Fairbank) -// -// Model of a foul. - -package game - -type Foul struct { - RuleId int - TeamId int - TimeInMatchSec float64 -} - -// Returns the rule for which the foul was assigned. -func (foul *Foul) Rule() *Rule { - return GetRuleById(foul.RuleId) -} - -// Returns the number of points that the foul adds to the opposing alliance's score. -func (foul *Foul) PointValue() int { - if foul.Rule() == nil || foul.Rule().IsRankingPoint { - return 0 - } - if foul.Rule().IsTechnical { - return 15 - } else { - return 3 - } -} diff --git a/game/match_timing.go b/game/match_timing.go index 1d8529e..25457ae 100644 --- a/game/match_timing.go +++ b/game/match_timing.go @@ -7,12 +7,6 @@ package game import "time" -const ( - powerPortAutoGracePeriodSec = 5 - PowerPortTeleopGracePeriodSec = 5 - rungAssessmentDelaySec = 5 -) - var MatchTiming = struct { WarmupDurationSec int AutoDurationSec int @@ -40,9 +34,3 @@ func GetDurationToTeleopEnd() time.Duration { return time.Duration(MatchTiming.WarmupDurationSec+MatchTiming.AutoDurationSec+MatchTiming.PauseDurationSec+ MatchTiming.TeleopDurationSec) * time.Second } - -// Returns true if the given time is within the proper range for assessing the level state of the shield generator rung. -func ShouldAssessRung(matchStartTime, currentTime time.Time) bool { - return currentTime.After(matchStartTime.Add(GetDurationToWarning())) && - currentTime.Before(matchStartTime.Add(GetDurationToTeleopEnd()+rungAssessmentDelaySec*time.Second)) -} diff --git a/game/match_timing_test.go b/game/match_timing_test.go deleted file mode 100644 index aa14f0c..0000000 --- a/game/match_timing_test.go +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2020 Team 254. All Rights Reserved. -// Author: pat@patfairbank.com (Patrick Fairbank) - -package game - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func TestShouldAssessRung(t *testing.T) { - assert.Equal(t, false, ShouldAssessRung(matchStartTime, timeAfterStart(0))) - assert.Equal(t, false, ShouldAssessRung(matchStartTime, timeAfterStart(121.9))) - assert.Equal(t, true, ShouldAssessRung(matchStartTime, timeAfterStart(122.1))) - assert.Equal(t, true, ShouldAssessRung(matchStartTime, timeAfterStart(152.1))) - assert.Equal(t, true, ShouldAssessRung(matchStartTime, timeAfterStart(156.9))) - assert.Equal(t, false, ShouldAssessRung(matchStartTime, timeAfterStart(157.1))) -} diff --git a/game/power_port.go b/game/power_port.go deleted file mode 100644 index e8ce43d..0000000 --- a/game/power_port.go +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2020 Team 254. All Rights Reserved. -// Author: pat@patfairbank.com (Patrick Fairbank) -// -// Scoring logic for the 2020 Power Port element. - -package game - -import ( - "time" -) - -type PowerPort struct { - AutoCellsBottom [2]int - AutoCellsOuter [2]int - AutoCellsInner [2]int - TeleopCellsBottom [4]int - TeleopCellsOuter [4]int - TeleopCellsInner [4]int -} - -// Updates the internal counting state of the power port given the current state of the hardware counts. Allows the -// score to accumulate before the match, since the counters will be reset in hardware. -func (powerPort *PowerPort) UpdateState(portCells [3]int, stage Stage, matchStartTime, currentTime time.Time) { - autoValidityDuration := GetDurationToAutoEnd() + powerPortAutoGracePeriodSec*time.Second - autoValidityCutoff := matchStartTime.Add(autoValidityDuration) - teleopValidityDuration := GetDurationToTeleopEnd() + PowerPortTeleopGracePeriodSec*time.Second - teleopValidityCutoff := matchStartTime.Add(teleopValidityDuration) - - newBottomCells := portCells[0] - totalPortCells(powerPort.AutoCellsBottom, powerPort.TeleopCellsBottom) - newOuterCells := portCells[1] - totalPortCells(powerPort.AutoCellsOuter, powerPort.TeleopCellsOuter) - newInnerCells := portCells[2] - totalPortCells(powerPort.AutoCellsInner, powerPort.TeleopCellsInner) - - if currentTime.Before(autoValidityCutoff) && stage <= Stage2 { - powerPort.AutoCellsBottom[stage] += newBottomCells - powerPort.AutoCellsOuter[stage] += newOuterCells - powerPort.AutoCellsInner[stage] += newInnerCells - } else if currentTime.Before(teleopValidityCutoff) { - powerPort.TeleopCellsBottom[stage] += newBottomCells - powerPort.TeleopCellsOuter[stage] += newOuterCells - powerPort.TeleopCellsInner[stage] += newInnerCells - } -} - -// Returns the total number of cells scored across all stages in a port level. -func totalPortCells(autoCells [2]int, teleopCells [4]int) int { - var total int - for _, stageCount := range autoCells { - total += stageCount - } - for _, stageCount := range teleopCells { - total += stageCount - } - return total -} diff --git a/game/power_port_test.go b/game/power_port_test.go deleted file mode 100644 index 414f8ee..0000000 --- a/game/power_port_test.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2020 Team 254. All Rights Reserved. -// Author: pat@patfairbank.com (Patrick Fairbank) - -package game - -import ( - "github.com/stretchr/testify/assert" - "testing" - "time" -) - -var matchStartTime = time.Unix(10, 0) - -func TestPowerPort(t *testing.T) { - var powerPort PowerPort - assertPowerPort(t, [3][2]int{}, [3][4]int{}, &powerPort) - - // Check before match start and during the autonomous period. - powerPort.UpdateState([3]int{0, 1, 2}, Stage1, matchStartTime, timeAfterStart(-1)) - assertPowerPort(t, [3][2]int{{0, 0}, {1, 0}, {2, 0}}, [3][4]int{}, &powerPort) - powerPort.UpdateState([3]int{0, 0, 0}, Stage1, matchStartTime, timeAfterStart(1)) - assertPowerPort(t, [3][2]int{{0, 0}, {0, 0}, {0, 0}}, [3][4]int{}, &powerPort) - powerPort.UpdateState([3]int{0, 1, 2}, Stage1, matchStartTime, timeAfterStart(2)) - assertPowerPort(t, [3][2]int{{0, 0}, {1, 0}, {2, 0}}, [3][4]int{}, &powerPort) - powerPort.UpdateState([3]int{3, 5, 2}, Stage1, matchStartTime, timeAfterStart(5)) - assertPowerPort(t, [3][2]int{{3, 0}, {5, 0}, {2, 0}}, [3][4]int{}, &powerPort) - - // Check boundary conditions around the auto end grace period. - powerPort.UpdateState([3]int{4, 6, 3}, Stage1, matchStartTime, timeAfterStart(16.9)) - assertPowerPort(t, [3][2]int{{4, 0}, {6, 0}, {3, 0}}, [3][4]int{}, &powerPort) - powerPort.UpdateState([3]int{5, 8, 6}, Stage2, matchStartTime, timeAfterStart(17.1)) - assertPowerPort(t, [3][2]int{{4, 1}, {6, 2}, {3, 3}}, [3][4]int{}, &powerPort) - powerPort.UpdateState([3]int{8, 10, 7}, Stage2, matchStartTime, timeAfterStart(19.9)) - assertPowerPort(t, [3][2]int{{4, 4}, {6, 4}, {3, 4}}, [3][4]int{}, &powerPort) - powerPort.UpdateState([3]int{8, 10, 8}, Stage2, matchStartTime, timeAfterStart(20.1)) - assertPowerPort(t, [3][2]int{{4, 4}, {6, 4}, {3, 4}}, [3][4]int{{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 1, 0, 0}}, - &powerPort) - - // Check during the teleoperated period. - powerPort.UpdateState([3]int{9, 10, 8}, Stage1, matchStartTime, timeAfterStart(30)) - assertPowerPort(t, [3][2]int{{4, 4}, {6, 4}, {3, 4}}, [3][4]int{{1, 0, 0, 0}, {0, 0, 0, 0}, {0, 1, 0, 0}}, - &powerPort) - powerPort.UpdateState([3]int{10, 12, 11}, Stage3, matchStartTime, timeAfterStart(30)) - assertPowerPort(t, [3][2]int{{4, 4}, {6, 4}, {3, 4}}, [3][4]int{{1, 0, 1, 0}, {0, 0, 2, 0}, {0, 1, 3, 0}}, - &powerPort) - powerPort.UpdateState([3]int{40, 32, 21}, StageExtra, matchStartTime, timeAfterStart(60)) - assertPowerPort(t, [3][2]int{{4, 4}, {6, 4}, {3, 4}}, [3][4]int{{1, 0, 1, 30}, {0, 0, 2, 20}, {0, 1, 3, 10}}, - &powerPort) - - // Check boundary conditions around the teleop end grace period. - powerPort.UpdateState([3]int{41, 32, 21}, StageExtra, matchStartTime, timeAfterStart(156.9)) - assertPowerPort(t, [3][2]int{{4, 4}, {6, 4}, {3, 4}}, [3][4]int{{1, 0, 1, 31}, {0, 0, 2, 20}, {0, 1, 3, 10}}, - &powerPort) - powerPort.UpdateState([3]int{42, 33, 22}, StageExtra, matchStartTime, timeAfterStart(157.1)) - assertPowerPort(t, [3][2]int{{4, 4}, {6, 4}, {3, 4}}, [3][4]int{{1, 0, 1, 31}, {0, 0, 2, 20}, {0, 1, 3, 10}}, - &powerPort) -} - -func assertPowerPort(t *testing.T, expectedAutoCells [3][2]int, expectedTeleopCells [3][4]int, powerPort *PowerPort) { - assert.Equal(t, expectedAutoCells[0], powerPort.AutoCellsBottom) - assert.Equal(t, expectedAutoCells[1], powerPort.AutoCellsOuter) - assert.Equal(t, expectedAutoCells[2], powerPort.AutoCellsInner) - assert.Equal(t, expectedTeleopCells[0], powerPort.TeleopCellsBottom) - assert.Equal(t, expectedTeleopCells[1], powerPort.TeleopCellsOuter) - assert.Equal(t, expectedTeleopCells[2], powerPort.TeleopCellsInner) -} - -func timeAfterStart(sec float32) time.Time { - return matchStartTime.Add(time.Duration(1000*sec) * time.Millisecond) -} diff --git a/game/ranking_fields.go b/game/ranking_fields.go old mode 100644 new mode 100755 index e8ce845..307db2d --- a/game/ranking_fields.go +++ b/game/ranking_fields.go @@ -16,7 +16,6 @@ type RankingFields struct { Wins int Losses int Ties int - Disqualifications int Played int } @@ -29,18 +28,12 @@ type Ranking struct { type Rankings []Ranking -func (fields *RankingFields) AddScoreSummary(ownScore *ScoreSummary, opponentScore *ScoreSummary, disqualified bool) { +func (fields *RankingFields) AddScoreSummary(ownScore *ScoreSummary, opponentScore *ScoreSummary) { fields.Played += 1 // Store a random value to be used as the last tiebreaker if necessary. fields.Random = rand.Float64() - if disqualified { - // Don't award any points. - fields.Disqualifications += 1 - return - } - // Assign ranking points and wins/losses/ties. if ownScore.Score > opponentScore.Score { fields.RankingPoints += 2 @@ -51,17 +44,11 @@ func (fields *RankingFields) AddScoreSummary(ownScore *ScoreSummary, opponentSco } else { fields.Losses += 1 } - if ownScore.ControlPanelRankingPoint { - fields.RankingPoints += 1 - } - if ownScore.EndgameRankingPoint { - fields.RankingPoints += 1 - } // Assign tiebreaker points. fields.AutoPoints += ownScore.AutoPoints fields.EndgamePoints += ownScore.EndgamePoints - fields.TeleopPoints += ownScore.TeleopPowerCellPoints + ownScore.ControlPanelPoints + fields.TeleopPoints += ownScore.TeleopPoints } // Helper function to implement the required interface for Sort. diff --git a/game/ranking_fields_test.go b/game/ranking_fields_test.go index 208f979..967bae1 100644 --- a/game/ranking_fields_test.go +++ b/game/ranking_fields_test.go @@ -14,40 +14,36 @@ func TestAddScoreSummary(t *testing.T) { rand.Seed(0) redScore := TestScore1() blueScore := TestScore2() - redSummary := redScore.Summarize(blueScore.Fouls, true) - blueSummary := blueScore.Summarize(redScore.Fouls, true) + redSummary := redScore.Summarize() + blueSummary := blueScore.Summarize() rankingFields := RankingFields{} // Add a loss. - rankingFields.AddScoreSummary(redSummary, blueSummary, false) - assert.Equal(t, RankingFields{1, 94, 75, 48, 0.9451961492941164, 0, 1, 0, 0, 1}, rankingFields) + rankingFields.AddScoreSummary(redSummary, blueSummary) + assert.Equal(t, RankingFields{2, 45, 30, 80, 0.9451961492941164, 1, 0, 0, 1}, rankingFields) // Add a win. - rankingFields.AddScoreSummary(blueSummary, redSummary, false) - assert.Equal(t, RankingFields{4, 111, 125, 200, 0.24496508529377975, 1, 1, 0, 0, 2}, rankingFields) + rankingFields.AddScoreSummary(blueSummary, redSummary) + assert.Equal(t, RankingFields{2, 60, 55, 120, 0.24496508529377975, 1, 1, 0, 2}, rankingFields) // Add a tie. - rankingFields.AddScoreSummary(redSummary, redSummary, false) - 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, 205, 200, 248, 0.05434383959970039, 1, 1, 1, 1, 4}, rankingFields) + rankingFields.AddScoreSummary(redSummary, redSummary) + assert.Equal(t, RankingFields{3, 105, 85, 200, 0.6559562651954052, 1, 1, 1, 3}, rankingFields) } func TestSortRankings(t *testing.T) { // Check tiebreakers. rankings := make(Rankings, 10) - rankings[0] = Ranking{1, 0, 0, RankingFields{50, 50, 50, 50, 0.49, 3, 2, 1, 0, 10}} - rankings[1] = Ranking{2, 0, 0, RankingFields{50, 50, 50, 50, 0.51, 3, 2, 1, 0, 10}} - rankings[2] = Ranking{3, 0, 0, RankingFields{50, 50, 50, 49, 0.50, 3, 2, 1, 0, 10}} - rankings[3] = Ranking{4, 0, 0, RankingFields{50, 50, 50, 51, 0.50, 3, 2, 1, 0, 10}} - rankings[4] = Ranking{5, 0, 0, RankingFields{50, 50, 49, 50, 0.50, 3, 2, 1, 0, 10}} - rankings[5] = Ranking{6, 0, 0, RankingFields{50, 50, 51, 50, 0.50, 3, 2, 1, 0, 10}} - rankings[6] = Ranking{7, 0, 0, RankingFields{50, 49, 50, 50, 0.50, 3, 2, 1, 0, 10}} - rankings[7] = Ranking{8, 0, 0, RankingFields{50, 51, 50, 50, 0.50, 3, 2, 1, 0, 10}} - rankings[8] = Ranking{9, 0, 0, RankingFields{49, 50, 50, 50, 0.50, 3, 2, 1, 0, 10}} - rankings[9] = Ranking{10, 0, 0, RankingFields{51, 50, 50, 50, 0.50, 3, 2, 1, 0, 10}} + rankings[0] = Ranking{1, 0, 0, RankingFields{50, 50, 50, 50, 0.49, 3, 2, 1, 10}} + rankings[1] = Ranking{2, 0, 0, RankingFields{50, 50, 50, 50, 0.51, 3, 2, 1, 10}} + rankings[2] = Ranking{3, 0, 0, RankingFields{50, 50, 50, 49, 0.50, 3, 2, 1, 10}} + rankings[3] = Ranking{4, 0, 0, RankingFields{50, 50, 50, 51, 0.50, 3, 2, 1, 10}} + rankings[4] = Ranking{5, 0, 0, RankingFields{50, 50, 49, 50, 0.50, 3, 2, 1, 10}} + rankings[5] = Ranking{6, 0, 0, RankingFields{50, 50, 51, 50, 0.50, 3, 2, 1, 10}} + rankings[6] = Ranking{7, 0, 0, RankingFields{50, 49, 50, 50, 0.50, 3, 2, 1, 10}} + rankings[7] = Ranking{8, 0, 0, RankingFields{50, 51, 50, 50, 0.50, 3, 2, 1, 10}} + rankings[8] = Ranking{9, 0, 0, RankingFields{49, 50, 50, 50, 0.50, 3, 2, 1, 10}} + rankings[9] = Ranking{10, 0, 0, RankingFields{51, 50, 50, 50, 0.50, 3, 2, 1, 10}} sort.Sort(rankings) assert.Equal(t, 10, rankings[0].TeamId) assert.Equal(t, 8, rankings[1].TeamId) @@ -62,9 +58,9 @@ func TestSortRankings(t *testing.T) { // Check with unequal number of matches played. rankings = make(Rankings, 3) - rankings[0] = Ranking{1, 0, 0, RankingFields{10, 25, 25, 25, 0.49, 3, 2, 1, 0, 5}} - rankings[1] = Ranking{2, 0, 0, RankingFields{19, 50, 50, 50, 0.51, 3, 2, 1, 0, 9}} - rankings[2] = Ranking{3, 0, 0, RankingFields{20, 50, 50, 50, 0.51, 3, 2, 1, 0, 10}} + rankings[0] = Ranking{1, 0, 0, RankingFields{10, 25, 25, 25, 0.49, 3, 2, 1, 5}} + rankings[1] = Ranking{2, 0, 0, RankingFields{19, 50, 50, 50, 0.51, 3, 2, 1, 9}} + rankings[2] = Ranking{3, 0, 0, RankingFields{20, 50, 50, 50, 0.51, 3, 2, 1, 10}} sort.Sort(rankings) assert.Equal(t, 2, rankings[0].TeamId) assert.Equal(t, 3, rankings[1].TeamId) diff --git a/game/rule.go b/game/rule.go deleted file mode 100644 index 37e8365..0000000 --- a/game/rule.go +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright 2020 Team 254. All Rights Reserved. -// Author: pat@patfairbank.com (Patrick Fairbank) -// -// Model of a game-specific rule. - -package game - -type Rule struct { - Id int - RuleNumber string - IsTechnical bool - IsRankingPoint bool - Description string -} - -// All rules from the 2020 game that carry point penalties. -var rules = []*Rule{ - {1, "S6", false, false, "DRIVE TEAMS may not extend any body part into the LOADING BAY Chute."}, - {2, "C8", false, false, "Strategies clearly aimed at forcing the opposing ALLIANCE to violate a rule are not in the spirit of FIRST Robotics Competition and not allowed."}, - {3, "C8", true, false, "Strategies clearly aimed at forcing the opposing ALLIANCE to violate a rule are not in the spirit of FIRST Robotics Competition and not allowed."}, - {4, "G3", false, false, "During AUTO, a ROBOT’s BUMPERS may not break the plane of their ALLIANCE’s SECTOR."}, - {5, "G3", true, false, "During AUTO, a ROBOT’s BUMPERS may not break the plane of their ALLIANCE’s SECTOR."}, - {6, "G4", false, false, "During AUTO, DRIVE TEAM members in ALLIANCE STATIONS may not contact anything in front of the STARTING LINES, unless for personal or equipment safety."}, - {7, "G5", false, false, "During AUTO, DRIVE TEAMS may not directly or indirectly interact with ROBOTS or OPERATOR CONSOLES unless for personal safety, OPERATOR CONSOLE safety, or pressing an E-Stop."}, - {8, "G6", false, false, "ROBOTS may not have greater-than-momentary CONTROL of more than five (5) POWER CELLS at a time, either directly or transitively through other objects."}, - {9, "G7", false, false, "ROBOTS may not intentionally eject POWER CELLS from the FIELD other than through the POWER PORT."}, - {10, "G8", true, false, "ROBOTS may not deliberately use POWER CELLS in an attempt to ease or amplify the challenge associated with FIELD elements."}, - {11, "G9", true, false, "A ROBOT whose BUMPERS are fully contained by their SECTOR may not cause POWER CELLS to travel into or through their opponent’s SECTOR."}, - {12, "G10", true, false, "A ROBOT whose BUMPERS are intersecting the opponent’s TARGET ZONE, TRENCH RUN, or LOADING ZONE may not contact opponent ROBOTS, regardless of who initiates contact."}, - {13, "G11", true, false, "An opponent ROBOT may not contact a ROBOT whose BUMPERS are intersecting its TARGET ZONE or LOADING ZONE, regardless of who initiates contact."}, - {14, "G12", false, true, "A ROBOT may not contact the opponent’s CONTROL PANEL, either directly, or transitively through a POWER CELL, if A. the opponent ROBOT is contacting that CONTROL PANEL, and B. the opponent’s POWER PORT has reached CAPACITY."}, - {15, "G12", true, false, "A ROBOT may not contact the opponent’s CONTROL PANEL, either directly, or transitively through a POWER CELL, if A. the opponent ROBOT is contacting that CONTROL PANEL, and B. the opponent’s POWER PORT has reached CAPACITY."}, - {16, "G13", true, false, "A ROBOT may not be fully supported by a partner ROBOT unless the partner ROBOT’S BUMPERS are intersecting its RENDEZVOUS POINT."}, - {17, "G14", true, false, "During the ENDGAME, a ROBOT may not contact, either directly or transitively through a POWER CELL, an opponent ROBOT whose BUMPERS are completely contained in its RENDEZVOUS POINT and not in contact with its GENERATOR SWITCH."}, - {18, "G16", false, false, "BUMPERS must be in the BUMPER ZONE during the MATCH, unless during the ENDGAME and A. a ROBOT’s BUMPERS are intersecting its RENDEZVOUS POINT or B. a ROBOT is supported by a partner ROBOT whose BUMPERS are intersecting its RENDEZVOUS POINT."}, - {19, "G17", true, false, "ROBOT height, as measured when it’s resting normally on a flat floor, may not exceed 45 in. (~114 cm) above the carpet during the MATCH, with the exception of ROBOTS intersecting their ALLIANCE’S RENDEZVOUS POINT during the ENDGAME."}, - {20, "G18", false, false, "ROBOTS may not extend more than 12 inches (~30 cm) beyond their FRAME PERIMETER."}, - {21, "G21", false, false, "ROBOTS may not PIN an opponent’s ROBOT for more than five (5) seconds."}, - {22, "G21", true, false, "ROBOTS may not PIN an opponent’s ROBOT for more than five (5) seconds."}, - {23, "G22", true, false, "Two or more ROBOTS that appear to a REFEREE to be working together may not isolate or close off any major component of MATCH play."}, - {24, "G23", true, false, "ROBOT actions that appear to be deliberate to a REFEREE and that cause damage or inhibition via attaching, tipping, or entangling to an opponent ROBOT are not allowed."}, - {25, "G24", false, false, "A ROBOT with a COMPONENT(S) outside its FRAME PERIMETER, other than BUMPERS, may not initiate direct contact with an opponent ROBOT inside the vertical projection of its FRAME PERIMETER using that COMPONENT."}, - {26, "G25", true, false, "Regardless of intent, a ROBOT may not initiate direct contact inside the vertical projection of an opponent ROBOT’S FRAME PERIMETER that damages or functionally impairs the opponent ROBOT."}, - {27, "G26", true, false, "ROBOTS and OPERATOR CONSOLES are prohibited from the following actions with regards to interaction with ARENA elements: grabbing, grasping, attaching, deforming, becoming entangled, damaging, suspending from."}, - {28, "H5", false, false, "During the MATCH, DRIVERS, COACHES, and HUMAN PLAYERS may not contact anything outside the ALLIANCE STATION and TECHNICIANS may not contact anything outside their designated area."}, - {29, "H6", false, false, "POWER CELLS may only be introduced to the FIELD A. during TELEOP, B. by a DRIVER or HUMAN PLAYER, and C. through the LOADING BAY."}, - {30, "H7", false, false, "During a MATCH, COACHES may not touch POWER CELLS, unless for safety purposes."}, - {31, "H9", false, false, "During TELEOP, an ALLIANCE may not have more than fifteen (15) POWER CELLS in their ALLIANCE STATION."}, - {32, "H10", false, false, "POWER CELLS must be stored on the LOADING BAY racks."}, - {33, "H10", true, false, "POWER CELLS must be stored on the LOADING BAY racks."}, - {34, "H16", true, false, "DRIVE TEAMS are prohibited from the following actions with regards to interaction with ARENA elements: climbing, hanging, deforming, damaging."}, -} -var ruleMap map[int]*Rule - -// Returns the rule having the given ID, or nil if no such rule exists. -func GetRuleById(id int) *Rule { - return GetAllRules()[id] -} - -// Returns a slice of all defined rules that carry point penalties. -func GetAllRules() map[int]*Rule { - if ruleMap == nil { - ruleMap = make(map[int]*Rule, len(rules)) - for _, rule := range rules { - ruleMap[rule.Id] = rule - } - } - return ruleMap -} diff --git a/game/rule_test.go b/game/rule_test.go deleted file mode 100644 index e7e4734..0000000 --- a/game/rule_test.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2020 Team 254. All Rights Reserved. -// Author: pat@patfairbank.com (Patrick Fairbank) - -package game - -import ( - "github.com/stretchr/testify/assert" - "testing" -) - -func TestGetRuleById(t *testing.T) { - assert.Nil(t, GetRuleById(0)) - assert.Equal(t, rules[0], GetRuleById(1)) - assert.Equal(t, rules[20], GetRuleById(21)) - assert.Nil(t, GetRuleById(1000)) -} - -func TestGetAllRules(t *testing.T) { - allRules := GetAllRules() - assert.Equal(t, len(rules), len(allRules)) - for _, rule := range rules { - assert.Equal(t, rule, allRules[rule.Id]) - } -} diff --git a/game/score.go b/game/score.go old mode 100644 new mode 100755 index bfed366..e9f6991 --- a/game/score.go +++ b/game/score.go @@ -5,214 +5,38 @@ package game -import "math" - type Score struct { - ExitedInitiationLine [3]bool - AutoCellsBottom [2]int - AutoCellsOuter [2]int - AutoCellsInner [2]int - TeleopCellsBottom [4]int - TeleopCellsOuter [4]int - TeleopCellsInner [4]int - ControlPanelStatus - EndgameStatuses [3]EndgameStatus - RungIsLevel bool - Fouls []Foul - ElimDq bool - PositionControlTargetColor ControlPanelColor + AutoPoints int + TeleopPoints int + EndgamePoints int } type ScoreSummary struct { - InitiationLinePoints int - AutoPowerCellPoints int - AutoPoints int - TeleopPowerCellPoints int - PowerCellPoints int - ControlPanelPoints int - EndgamePoints int - FoulPoints int - Score int - StagePowerCellsRemaining [3]int - StagesActivated [3]bool - ControlPanelRankingPoint bool - EndgameRankingPoint bool + AutoPoints int + TeleopPoints int + EndgamePoints int + Score 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 ( - Stage1 Stage = iota - Stage2 - Stage3 - StageExtra -) - -// Represents the state of a robot at the end of the match. -type EndgameStatus int - -const ( - EndgameNone EndgameStatus = iota - EndgamePark - EndgameHang -) - // Calculates and returns the summary fields used for ranking and display. -func (score *Score) Summarize(opponentFouls []Foul, teleopStarted bool) *ScoreSummary { +func (score *Score) Summarize() *ScoreSummary { summary := new(ScoreSummary) - // Leave the score at zero if the team was disqualified. - if score.ElimDq { - return summary - } - - // 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] - } - summary.PowerCellPoints = summary.AutoPowerCellPoints + summary.TeleopPowerCellPoints - - // Calculate control panel points and stages. - for i := Stage1; i <= Stage3; i++ { - summary.StagesActivated[i] = score.stageActivated(i, teleopStarted) - summary.StagePowerCellsRemaining[i] = int(math.Max(0, float64(StageCapacities[i]-score.stagePowerCells(i)))) - } - if summary.StagesActivated[Stage2] { - summary.ControlPanelPoints += 10 - } - if summary.StagesActivated[Stage3] { - summary.ControlPanelPoints += 20 - summary.ControlPanelRankingPoint = true - } - - // Calculate endgame points. - anyHang := false - for _, status := range score.EndgameStatuses { - if status == EndgamePark { - summary.EndgamePoints += 5 - } else if status == EndgameHang { - summary.EndgamePoints += 25 - anyHang = true - } - } - if score.RungIsLevel && anyHang { - summary.EndgamePoints += 15 - } - summary.EndgameRankingPoint = summary.EndgamePoints >= 65 - - // Calculate penalty points. - for _, foul := range opponentFouls { - summary.FoulPoints += foul.PointValue() - } - - // Check for the opponent fouls that automatically trigger a ranking point. - for _, foul := range opponentFouls { - if foul.Rule() != nil && foul.Rule().IsRankingPoint { - summary.ControlPanelRankingPoint = true - break - } - } - - summary.Score = summary.AutoPoints + summary.TeleopPowerCellPoints + summary.ControlPanelPoints + - summary.EndgamePoints + summary.FoulPoints + summary.AutoPoints = score.AutoPoints + summary.TeleopPoints = score.TeleopPoints + summary.EndgamePoints = score.EndgamePoints + summary.Score = summary.AutoPoints + summary.TeleopPoints + summary.EndgamePoints 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.ExitedInitiationLine != other.ExitedInitiationLine || - score.AutoCellsBottom != other.AutoCellsBottom || - score.AutoCellsOuter != other.AutoCellsOuter || - score.AutoCellsInner != other.AutoCellsInner || - score.TeleopCellsBottom != other.TeleopCellsBottom || - score.TeleopCellsOuter != other.TeleopCellsOuter || - score.TeleopCellsInner != other.TeleopCellsInner || - score.ControlPanelStatus != other.ControlPanelStatus || - score.EndgameStatuses != other.EndgameStatuses || - score.RungIsLevel != other.RungIsLevel || - score.ElimDq != other.ElimDq || - len(score.Fouls) != len(other.Fouls) { + if score.AutoPoints != other.AutoPoints || + score.TeleopPoints != other.TeleopPoints || + score.EndgamePoints != other.EndgamePoints { return false } - for i, foul := range score.Fouls { - if foul != other.Fouls[i] { - return false - } - } - return true } - -// Returns the Stage (1-3) that the score represents, in terms of which Stage scored power cells should count towards. -func (score *Score) CellCountingStage(teleopStarted bool) Stage { - if score.stageActivated(Stage3, teleopStarted) { - return StageExtra - } - if score.stageActivated(Stage2, teleopStarted) { - return Stage3 - } - if score.stageActivated(Stage1, teleopStarted) { - return Stage2 - } - return Stage1 -} - -// Returns true if the preconditions are satisfied for the given Stage to be activated. -func (score *Score) StageAtCapacity(stage Stage, teleopStarted bool) bool { - if stage > Stage1 && !score.stageActivated(stage-1, teleopStarted) { - return false - } - if capacity, ok := StageCapacities[stage]; ok && score.stagePowerCells(stage) >= capacity { - return true - } - return false -} - -// Returns true if the given Stage has been activated. -func (score *Score) stageActivated(stage Stage, teleopStarted bool) bool { - if score.StageAtCapacity(stage, teleopStarted) { - switch stage { - case Stage1: - return teleopStarted - case Stage2: - return score.ControlPanelStatus >= ControlPanelRotation - case Stage3: - return score.ControlPanelStatus == ControlPanelPosition - } - } - 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 -} diff --git a/game/score_test.go b/game/score_test.go index 8729be0..16b5090 100644 --- a/game/score_test.go +++ b/game/score_test.go @@ -12,179 +12,15 @@ func TestScoreSummary(t *testing.T) { redScore := TestScore1() blueScore := TestScore2() - redSummary := redScore.Summarize(blueScore.Fouls, true) - 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, 122, redSummary.PowerCellPoints) - assert.Equal(t, 10, redSummary.ControlPanelPoints) - assert.Equal(t, 75, redSummary.EndgamePoints) - assert.Equal(t, 0, redSummary.FoulPoints) - assert.Equal(t, 217, redSummary.Score) - assert.Equal(t, [3]int{0, 0, 18}, redSummary.StagePowerCellsRemaining) - assert.Equal(t, [3]bool{true, true, false}, redSummary.StagesActivated) - assert.Equal(t, false, redSummary.ControlPanelRankingPoint) - assert.Equal(t, true, redSummary.EndgameRankingPoint) + redSummary := redScore.Summarize() + assert.Equal(t, 45, redSummary.AutoPoints) + assert.Equal(t, 80, redSummary.TeleopPoints) + assert.Equal(t, 30, redSummary.EndgamePoints) - blueSummary := blueScore.Summarize(redScore.Fouls, true) - 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, 134, blueSummary.PowerCellPoints) - 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]int{0, 0, 0}, blueSummary.StagePowerCellsRemaining) - 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, 18, blueScore.Summarize(redScore.Fouls, true).FoulPoints) - - // Test elimination disqualification. - redScore.ElimDq = true - assert.Equal(t, 0, redScore.Summarize(blueScore.Fouls, true).Score) - assert.NotEqual(t, 0, blueScore.Summarize(blueScore.Fouls, true).Score) - blueScore.ElimDq = true - assert.Equal(t, 0, blueScore.Summarize(redScore.Fouls, true).Score) -} - -func TestScoreSummaryRungIsLevel(t *testing.T) { - var score Score - assert.Equal(t, 0, score.Summarize([]Foul{}, true).EndgamePoints) - score.RungIsLevel = true - assert.Equal(t, 0, score.Summarize([]Foul{}, true).EndgamePoints) - - score.RungIsLevel = false - score.EndgameStatuses = [3]EndgameStatus{EndgamePark, EndgamePark, EndgamePark} - assert.Equal(t, 15, score.Summarize([]Foul{}, true).EndgamePoints) - score.RungIsLevel = true - assert.Equal(t, 15, score.Summarize([]Foul{}, true).EndgamePoints) - - score.RungIsLevel = false - score.EndgameStatuses = [3]EndgameStatus{EndgameHang, EndgamePark, EndgamePark} - assert.Equal(t, 35, score.Summarize([]Foul{}, true).EndgamePoints) - score.RungIsLevel = true - assert.Equal(t, 50, score.Summarize([]Foul{}, true).EndgamePoints) - - score.RungIsLevel = false - score.EndgameStatuses = [3]EndgameStatus{EndgameHang, EndgamePark, EndgameHang} - assert.Equal(t, 55, score.Summarize([]Foul{}, true).EndgamePoints) - score.RungIsLevel = true - assert.Equal(t, 70, score.Summarize([]Foul{}, true).EndgamePoints) - - score.RungIsLevel = false - score.EndgameStatuses = [3]EndgameStatus{EndgameHang, EndgameHang, EndgameHang} - assert.Equal(t, 75, score.Summarize([]Foul{}, true).EndgamePoints) - score.RungIsLevel = true - assert.Equal(t, 90, score.Summarize([]Foul{}, true).EndgamePoints) - - score.RungIsLevel = false - score.EndgameStatuses = [3]EndgameStatus{EndgameNone, EndgameNone, EndgameNone} - assert.Equal(t, 0, score.Summarize([]Foul{}, true).EndgamePoints) - score.RungIsLevel = true - assert.Equal(t, 0, score.Summarize([]Foul{}, true).EndgamePoints) -} - -func TestScoreSummaryBoundaryConditions(t *testing.T) { - // Test control panel boundary conditions. - score := TestScore2() - summary := score.Summarize(score.Fouls, true) - assert.Equal(t, StageExtra, score.CellCountingStage(true)) - assert.Equal(t, [3]int{0, 0, 0}, summary.StagePowerCellsRemaining) - 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, true) - assert.Equal(t, Stage1, score.CellCountingStage(true)) - assert.Equal(t, [3]int{1, 0, 0}, summary.StagePowerCellsRemaining) - 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]++ - - summary = score.Summarize(score.Fouls, false) - assert.Equal(t, Stage1, score.CellCountingStage(false)) - assert.Equal(t, [3]int{0, 0, 0}, summary.StagePowerCellsRemaining) - assert.Equal(t, [3]bool{false, false, false}, summary.StagesActivated) - assert.Equal(t, false, summary.ControlPanelRankingPoint) - assert.Equal(t, 189, summary.Score) - - score.TeleopCellsOuter[1] -= 2 - summary = score.Summarize(score.Fouls, true) - assert.Equal(t, Stage2, score.CellCountingStage(true)) - assert.Equal(t, [3]int{0, 2, 0}, summary.StagePowerCellsRemaining) - assert.Equal(t, [3]bool{true, false, false}, summary.StagesActivated) - assert.Equal(t, false, summary.ControlPanelRankingPoint) - assert.Equal(t, 185, summary.Score) - score.TeleopCellsOuter[1] += 2 - - score.ControlPanelStatus = ControlPanelNone - summary = score.Summarize(score.Fouls, true) - assert.Equal(t, Stage2, score.CellCountingStage(true)) - assert.Equal(t, [3]int{0, 0, 0}, summary.StagePowerCellsRemaining) - assert.Equal(t, [3]bool{true, false, false}, summary.StagesActivated) - assert.Equal(t, false, summary.ControlPanelRankingPoint) - assert.Equal(t, 189, summary.Score) - score.ControlPanelStatus = ControlPanelPosition - - score.TeleopCellsInner[2] -= 5 - summary = score.Summarize(score.Fouls, true) - assert.Equal(t, Stage3, score.CellCountingStage(true)) - assert.Equal(t, [3]int{0, 0, 3}, summary.StagePowerCellsRemaining) - assert.Equal(t, [3]bool{true, true, false}, summary.StagesActivated) - assert.Equal(t, false, summary.ControlPanelRankingPoint) - assert.Equal(t, 184, summary.Score) - score.TeleopCellsInner[2] += 5 - - score.ControlPanelStatus = ControlPanelRotation - summary = score.Summarize(score.Fouls, true) - assert.Equal(t, Stage3, score.CellCountingStage(true)) - assert.Equal(t, [3]int{0, 0, 0}, summary.StagePowerCellsRemaining) - 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, true).EndgameRankingPoint) - score.EndgameStatuses[0] = EndgameNone - assert.Equal(t, false, score.Summarize(score.Fouls, true).EndgameRankingPoint) - score.RungIsLevel = true - assert.Equal(t, true, score.Summarize(score.Fouls, true).EndgameRankingPoint) - score.EndgameStatuses[2] = EndgamePark - assert.Equal(t, false, score.Summarize(score.Fouls, true).EndgameRankingPoint) -} - -func TestScoreSummaryRankingPointFoul(t *testing.T) { - fouls := []Foul{{14, 0, 0}} - score1 := TestScore1() - score2 := TestScore2() - - summary := score1.Summarize([]Foul{}, true) - assert.Equal(t, 0, summary.FoulPoints) - assert.Equal(t, false, summary.ControlPanelRankingPoint) - assert.Equal(t, true, summary.EndgameRankingPoint) - summary = score1.Summarize(fouls, true) - assert.Equal(t, 0, summary.FoulPoints) - assert.Equal(t, true, summary.ControlPanelRankingPoint) - assert.Equal(t, true, summary.EndgameRankingPoint) - - summary = score2.Summarize([]Foul{}, true) - assert.Equal(t, 0, summary.FoulPoints) - assert.Equal(t, true, summary.ControlPanelRankingPoint) - assert.Equal(t, false, summary.EndgameRankingPoint) - summary = score2.Summarize(fouls, true) - assert.Equal(t, 0, summary.FoulPoints) - assert.Equal(t, true, summary.ControlPanelRankingPoint) - assert.Equal(t, false, summary.EndgameRankingPoint) + blueSummary := blueScore.Summarize() + assert.Equal(t, 15, blueSummary.AutoPoints) + assert.Equal(t, 40, blueSummary.TeleopPoints) + assert.Equal(t, 25, blueSummary.EndgamePoints) } func TestScoreEquals(t *testing.T) { @@ -198,77 +34,17 @@ func TestScoreEquals(t *testing.T) { assert.False(t, score3.Equals(score1)) score2 = TestScore1() - score2.ExitedInitiationLine[0] = false + score2.AutoPoints = 20 assert.False(t, score1.Equals(score2)) assert.False(t, score2.Equals(score1)) score2 = TestScore1() - score2.AutoCellsBottom[1] = 3 + score2.TeleopPoints = 35 assert.False(t, score1.Equals(score2)) assert.False(t, score2.Equals(score1)) score2 = TestScore1() - score2.AutoCellsOuter[0] = 7 - assert.False(t, score1.Equals(score2)) - assert.False(t, score2.Equals(score1)) - - score2 = TestScore1() - score2.AutoCellsInner[1] = 8 - assert.False(t, score1.Equals(score2)) - assert.False(t, score2.Equals(score1)) - - score2 = TestScore1() - score2.TeleopCellsBottom[2] = 30 - assert.False(t, score1.Equals(score2)) - assert.False(t, score2.Equals(score1)) - - score2 = TestScore1() - score2.TeleopCellsOuter[1] = 31 - assert.False(t, score1.Equals(score2)) - assert.False(t, score2.Equals(score1)) - - score2 = TestScore1() - score2.TeleopCellsInner[0] = 32 - assert.False(t, score1.Equals(score2)) - assert.False(t, score2.Equals(score1)) - - score2 = TestScore1() - score2.ControlPanelStatus = ControlPanelNone - assert.False(t, score1.Equals(score2)) - assert.False(t, score2.Equals(score1)) - - score2 = TestScore1() - score2.EndgameStatuses[1] = EndgameNone - 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)) - - score2 = TestScore1() - score2.Fouls = []Foul{} - assert.False(t, score1.Equals(score2)) - assert.False(t, score2.Equals(score1)) - - score2 = TestScore1() - score2.Fouls[0].RuleId = 1 - assert.False(t, score1.Equals(score2)) - assert.False(t, score2.Equals(score1)) - - score2 = TestScore1() - score2.Fouls[0].TeamId += 1 - assert.False(t, score1.Equals(score2)) - assert.False(t, score2.Equals(score1)) - - score2 = TestScore1() - score2.Fouls[0].TimeInMatchSec += 1 - assert.False(t, score1.Equals(score2)) - assert.False(t, score2.Equals(score1)) - - score2 = TestScore1() - score2.ElimDq = !score2.ElimDq + score2.EndgamePoints = 15 assert.False(t, score1.Equals(score2)) assert.False(t, score2.Equals(score1)) } diff --git a/game/test_helpers.go b/game/test_helpers.go old mode 100644 new mode 100755 index 17c1ed7..0e09382 --- a/game/test_helpers.go +++ b/game/test_helpers.go @@ -6,48 +6,25 @@ package game func TestScore1() *Score { - fouls := []Foul{ - {17, 25, 150}, - {18, 1868, 0}, - {19, 25, 25.2}, - } return &Score{ - ExitedInitiationLine: [3]bool{true, true, false}, - AutoCellsBottom: [2]int{2, 1}, - AutoCellsOuter: [2]int{6, 0}, - AutoCellsInner: [2]int{4, 5}, - TeleopCellsBottom: [4]int{0, 11, 2, 0}, - TeleopCellsOuter: [4]int{0, 5, 0, 0}, - TeleopCellsInner: [4]int{0, 5, 0, 0}, - ControlPanelStatus: ControlPanelRotation, - EndgameStatuses: [3]EndgameStatus{EndgameHang, EndgameHang, EndgameHang}, - RungIsLevel: false, - Fouls: fouls, - ElimDq: false, + AutoPoints: 45, + TeleopPoints: 80, + EndgamePoints: 30, } } func TestScore2() *Score { return &Score{ - ExitedInitiationLine: [3]bool{false, true, false}, - AutoCellsBottom: [2]int{0, 0}, - AutoCellsOuter: [2]int{3, 0}, - AutoCellsInner: [2]int{0, 0}, - TeleopCellsBottom: [4]int{2, 0, 2, 0}, - TeleopCellsOuter: [4]int{2, 14, 0, 1}, - TeleopCellsInner: [4]int{2, 6, 20, 0}, - ControlPanelStatus: ControlPanelPosition, - EndgameStatuses: [3]EndgameStatus{EndgamePark, EndgamePark, EndgameHang}, - RungIsLevel: true, - Fouls: []Foul{}, - ElimDq: false, + AutoPoints: 15, + TeleopPoints: 40, + EndgamePoints: 25, } } func TestRanking1() *Ranking { - return &Ranking{254, 1, 0, RankingFields{20, 625, 90, 554, 0.254, 3, 2, 1, 0, 10}} + return &Ranking{254, 1, 0, RankingFields{20, 625, 90, 554, 0.254, 3, 2, 1, 10}} } func TestRanking2() *Ranking { - return &Ranking{1114, 2, 1, RankingFields{18, 700, 625, 90, 0.1114, 1, 3, 2, 0, 10}} + return &Ranking{1114, 2, 1, RankingFields{18, 700, 625, 90, 0.1114, 1, 3, 2, 10}} } diff --git a/model/event_settings.go b/model/event_settings.go old mode 100644 new mode 100755 index 1092485..e748f21 --- a/model/event_settings.go +++ b/model/event_settings.go @@ -38,9 +38,6 @@ type EventSettings struct { PauseDurationSec int TeleopDurationSec int WarningRemainingDurationSec int - Stage1Capacity int - Stage2Capacity int - Stage3Capacity int } const eventSettingsId = 0 @@ -64,9 +61,6 @@ func (database *Database) GetEventSettings() (*EventSettings, error) { eventSettings.PauseDurationSec = game.MatchTiming.PauseDurationSec eventSettings.TeleopDurationSec = game.MatchTiming.TeleopDurationSec eventSettings.WarningRemainingDurationSec = game.MatchTiming.WarningRemainingDurationSec - eventSettings.Stage1Capacity = game.StageCapacities[game.Stage1] - eventSettings.Stage2Capacity = game.StageCapacities[game.Stage2] - eventSettings.Stage3Capacity = game.StageCapacities[game.Stage3] err = database.eventSettingsMap.Insert(eventSettings) if err != nil { diff --git a/model/event_settings_test.go b/model/event_settings_test.go index 0c3344a..18227e4 100644 --- a/model/event_settings_test.go +++ b/model/event_settings_test.go @@ -16,8 +16,7 @@ func TestEventSettingsReadWrite(t *testing.T) { assert.Equal(t, EventSettings{Id: 0, Name: "Untitled Event", NumElimAlliances: 8, SelectionRound2Order: "L", SelectionRound3Order: "", TBADownloadEnabled: true, ApTeamChannel: 157, ApAdminChannel: 0, ApAdminWpaKey: "1234Five", WarmupDurationSec: 0, AutoDurationSec: 15, PauseDurationSec: 2, - TeleopDurationSec: 135, WarningRemainingDurationSec: 30, Stage1Capacity: 9, Stage2Capacity: 20, - Stage3Capacity: 20}, *eventSettings) + TeleopDurationSec: 135, WarningRemainingDurationSec: 30}, *eventSettings) eventSettings.Name = "Chezy Champs" eventSettings.NumElimAlliances = 6 diff --git a/model/match_result.go b/model/match_result.go old mode 100644 new mode 100755 index 7cdc168..52d378d --- a/model/match_result.go +++ b/model/match_result.go @@ -17,8 +17,6 @@ type MatchResult struct { MatchType string RedScore *game.Score BlueScore *game.Score - RedCards map[string]string - BlueCards map[string]string } type MatchResultDb struct { @@ -28,8 +26,6 @@ type MatchResultDb struct { MatchType string RedScoreJson string BlueScoreJson string - RedCardsJson string - BlueCardsJson string } // Returns a new match result object with empty slices instead of nil. @@ -37,8 +33,6 @@ func NewMatchResult() *MatchResult { matchResult := new(MatchResult) matchResult.RedScore = new(game.Score) matchResult.BlueScore = new(game.Score) - matchResult.RedCards = make(map[string]string) - matchResult.BlueCards = make(map[string]string) return matchResult } @@ -95,30 +89,13 @@ func (database *Database) TruncateMatchResults() error { } // Calculates and returns the summary fields used for ranking and display for the red alliance. -func (matchResult *MatchResult) RedScoreSummary(teleopStarted bool) *game.ScoreSummary { - return matchResult.RedScore.Summarize(matchResult.BlueScore.Fouls, teleopStarted) +func (matchResult *MatchResult) RedScoreSummary() *game.ScoreSummary { + return matchResult.RedScore.Summarize() } // Calculates and returns the summary fields used for ranking and display for the blue alliance. -func (matchResult *MatchResult) BlueScoreSummary(teleopStarted bool) *game.ScoreSummary { - return matchResult.BlueScore.Summarize(matchResult.RedScore.Fouls, teleopStarted) -} - -// Checks the score for disqualifications or a tie and adjusts it appropriately. -func (matchResult *MatchResult) CorrectEliminationScore() { - matchResult.RedScore.ElimDq = false - for _, card := range matchResult.RedCards { - if card == "red" { - matchResult.RedScore.ElimDq = true - } - } - for _, card := range matchResult.BlueCards { - if card == "red" { - matchResult.BlueScore.ElimDq = true - } - } - - // No elimination tiebreakers. +func (matchResult *MatchResult) BlueScoreSummary() *game.ScoreSummary { + return matchResult.BlueScore.Summarize() } // Converts the nested struct MatchResult to the DB version that has JSON fields. @@ -131,12 +108,6 @@ func (matchResult *MatchResult) Serialize() (*MatchResultDb, error) { if err := serializeHelper(&matchResultDb.BlueScoreJson, matchResult.BlueScore); err != nil { return nil, err } - if err := serializeHelper(&matchResultDb.RedCardsJson, matchResult.RedCards); err != nil { - return nil, err - } - if err := serializeHelper(&matchResultDb.BlueCardsJson, matchResult.BlueCards); err != nil { - return nil, err - } return &matchResultDb, nil } @@ -150,11 +121,5 @@ func (matchResultDb *MatchResultDb) Deserialize() (*MatchResult, error) { if err := json.Unmarshal([]byte(matchResultDb.BlueScoreJson), &matchResult.BlueScore); err != nil { return nil, err } - if err := json.Unmarshal([]byte(matchResultDb.RedCardsJson), &matchResult.RedCards); err != nil { - return nil, err - } - if err := json.Unmarshal([]byte(matchResultDb.BlueCardsJson), &matchResult.BlueCards); err != nil { - return nil, err - } return &matchResult, nil } diff --git a/model/match_result_test.go b/model/match_result_test.go index 8da80d0..6a42c84 100644 --- a/model/match_result_test.go +++ b/model/match_result_test.go @@ -4,7 +4,6 @@ package model import ( - "github.com/Team254/cheesy-arena/game" "github.com/stretchr/testify/assert" "testing" ) @@ -26,7 +25,6 @@ func TestMatchResultCrud(t *testing.T) { assert.Nil(t, err) assert.Equal(t, matchResult, matchResult2) - matchResult.BlueScore.EndgameStatuses = [3]game.EndgameStatus{game.EndgameHang, game.EndgameNone, game.EndgamePark} db.SaveMatchResult(matchResult) matchResult2, err = db.GetMatchResultForMatch(254) assert.Nil(t, err) diff --git a/model/team.go b/model/team.go index d267695..acb5419 100644 --- a/model/team.go +++ b/model/team.go @@ -16,7 +16,6 @@ type Team struct { RobotName string Accomplishments string WpaKey string - YellowCard bool HasConnected bool FtaNotes string } diff --git a/model/test_helpers.go b/model/test_helpers.go old mode 100644 new mode 100755 index 96451f2..8ba49b7 --- a/model/test_helpers.go +++ b/model/test_helpers.go @@ -27,8 +27,6 @@ func BuildTestMatchResult(matchId int, playNumber int) *MatchResult { matchResult := &MatchResult{MatchId: matchId, PlayNumber: playNumber, MatchType: "qualification"} matchResult.RedScore = game.TestScore1() matchResult.BlueScore = game.TestScore2() - matchResult.RedCards = map[string]string{"1868": "yellow"} - matchResult.BlueCards = map[string]string{} return matchResult } diff --git a/partner/tba.go b/partner/tba.go old mode 100644 new mode 100755 index 96ffb96..b6fddde --- a/partner/tba.go +++ b/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" @@ -37,7 +36,6 @@ type TbaMatch struct { SetNumber int `json:"set_number"` MatchNumber int `json:"match_number"` Alliances map[string]*TbaAlliance `json:"alliances"` - ScoreBreakdown map[string]*TbaScoreBreakdown `json:"score_breakdown"` TimeString string `json:"time_string"` TimeUtc string `json:"time_utc"` } @@ -49,40 +47,6 @@ type TbaAlliance struct { Score *int `json:"score"` } -type TbaScoreBreakdown struct { - InitLineRobot1 string `json:"initLineRobot1"` - InitLineRobot2 string `json:"initLineRobot2"` - InitLineRobot3 string `json:"initLineRobot3"` - AutoCellsBottom int `json:"autoCellsBottom"` - AutoCellsOuter int `json:"autoCellsOuter"` - AutoCellsInner int `json:"autoCellsInner"` - TeleopCellsBottom int `json:"teleopCellsBottom"` - TeleopCellsOuter int `json:"teleopCellsOuter"` - TeleopCellsInner int `json:"teleopCellsInner"` - Stage1Activated bool `json:"stage1Activated"` - Stage2Activated bool `json:"stage2Activated"` - Stage3Activated bool `json:"stage3Activated"` - Stage3TargetColor string `json:"stage3TargetColor"` - EndgameRobot1 string `json:"endgameRobot1"` - EndgameRobot2 string `json:"endgameRobot2"` - EndgameRobot3 string `json:"endgameRobot3"` - EndgameRungIsLevel string `json:"endgameRungIsLevel"` - FoulCount int `json:"foulCount"` - TechFoulCount int `json:"techFoulCount"` - AutoInitLinePoints int `json:"autoInitLinePoints"` - AutoCellPoints int `json:"autoCellPoints"` - AutoPoints int `json:"autoPoints"` - TeleopCellPoints int `json:"teleopCellPoints"` - ControlPanelPoints int `json:"controlPanelPoints"` - EndgamePoints int `json:"endgamePoints"` - TeleopPoints int `json:"teleopPoints"` - FoulPoints int `json:"foulPoints"` - TotalPoints int `json:"totalPoints"` - ShieldEnergizedRankingPoint bool `json:"shieldEnergizedRankingPoint"` - ShieldOperationalRankingPoint bool `json:"shieldOperationalRankingPoint"` - RP int `json:"rp"` -} - type TbaRanking struct { TeamKey string `json:"team_key"` Rank int `json:"rank"` @@ -137,12 +101,6 @@ type TbaPublishedAward struct { Awardee string `json:"awardee"` } -var exitedInitLineMapping = map[bool]string{false: "None", true: "Exited"} -var controlPanelColorMapping = map[game.ControlPanelColor]string{game.ColorUnknown: "Unknown", game.ColorRed: "Red", - game.ColorGreen: "Green", game.ColorBlue: "Blue", game.ColorYellow: "Yellow"} -var endgameMapping = []string{"None", "Park", "Hang"} -var rungIsLevelMapping = map[bool]string{false: "NotLevel", true: "IsLevel"} - func NewTbaClient(eventCode, secretId, secret string) *TbaClient { return &TbaClient{BaseUrl: tbaBaseUrl, eventCode: eventCode, secretId: secretId, secret: secret, eventNamesCache: make(map[string]string)} @@ -316,31 +274,31 @@ func (client *TbaClient) PublishMatches(database *model.Database) error { matchNumber, _ := strconv.Atoi(match.DisplayName) // Fill in scores if the match has been played. - var scoreBreakdown map[string]*TbaScoreBreakdown + var redScoreSummary, blueScoreSummary int var redScore, blueScore *int - var redCards, blueCards map[string]string if match.IsComplete() { matchResult, err := database.GetMatchResultForMatch(match.Id) if err != nil { return err } if matchResult != nil { - scoreBreakdown = make(map[string]*TbaScoreBreakdown) - scoreBreakdown["red"] = createTbaScoringBreakdown(&match, matchResult, "red") - scoreBreakdown["blue"] = createTbaScoringBreakdown(&match, matchResult, "blue") - redScore = &scoreBreakdown["red"].TotalPoints - blueScore = &scoreBreakdown["blue"].TotalPoints - redCards = matchResult.RedCards - blueCards = matchResult.BlueCards + redScoreSummary = matchResult.RedScore.AutoPoints + + matchResult.RedScore.TeleopPoints + + matchResult.RedScore.EndgamePoints + blueScoreSummary = matchResult.BlueScore.AutoPoints + + matchResult.BlueScore.TeleopPoints + + matchResult.BlueScore.EndgamePoints + redScore = &redScoreSummary + blueScore = &blueScoreSummary } } alliances := make(map[string]*TbaAlliance) alliances["red"] = createTbaAlliance([3]int{match.Red1, match.Red2, match.Red3}, [3]bool{match.Red1IsSurrogate, - match.Red2IsSurrogate, match.Red3IsSurrogate}, redScore, redCards) + match.Red2IsSurrogate, match.Red3IsSurrogate}, redScore) alliances["blue"] = createTbaAlliance([3]int{match.Blue1, match.Blue2, match.Blue3}, - [3]bool{match.Blue1IsSurrogate, match.Blue2IsSurrogate, match.Blue3IsSurrogate}, blueScore, blueCards) + [3]bool{match.Blue1IsSurrogate, match.Blue2IsSurrogate, match.Blue3IsSurrogate}, blueScore) - tbaMatches[i] = TbaMatch{"qm", 0, matchNumber, alliances, scoreBreakdown, match.Time.Local().Format("3:04 PM"), + tbaMatches[i] = TbaMatch{"qm", 0, matchNumber, alliances, match.Time.Local().Format("3:04 PM"), match.Time.UTC().Format("2006-01-02T15:04:05")} if match.Type == "elimination" { tbaMatches[i].CompLevel = map[int]string{1: "f", 2: "sf", 4: "qf", 8: "ef"}[match.ElimRound] @@ -379,7 +337,7 @@ func (client *TbaClient) PublishRankings(database *model.Database) error { tbaRankings[i] = TbaRanking{getTbaTeam(ranking.TeamId), ranking.Rank, 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, + fmt.Sprintf("%d-%d-%d", ranking.Wins, ranking.Losses, ranking.Ties), 0, ranking.Played} } jsonBody, err := json.Marshal(TbaRankings{breakdowns, tbaRankings}) @@ -501,7 +459,7 @@ func (client *TbaClient) postRequest(resource string, action string, body []byte return httpClient.Do(request) } -func createTbaAlliance(teamIds [3]int, surrogates [3]bool, score *int, cards map[string]string) *TbaAlliance { +func createTbaAlliance(teamIds [3]int, surrogates [3]bool, score *int) *TbaAlliance { alliance := TbaAlliance{Surrogates: []string{}, Dqs: []string{}, Score: score} for i, teamId := range teamIds { teamKey := getTbaTeam(teamId) @@ -509,79 +467,11 @@ func createTbaAlliance(teamIds [3]int, surrogates [3]bool, score *int, cards map if surrogates[i] { alliance.Surrogates = append(alliance.Surrogates, teamKey) } - if cards != nil { - if card, ok := cards[strconv.Itoa(teamId)]; ok && card == "red" { - alliance.Dqs = append(alliance.Dqs, teamKey) - } - } } return &alliance } -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(true) - opponentScoreSummary = matchResult.BlueScoreSummary(true) - } else { - score = matchResult.BlueScore - scoreSummary = matchResult.BlueScoreSummary(true) - opponentScoreSummary = matchResult.RedScoreSummary(true) - } - - breakdown.InitLineRobot1 = exitedInitLineMapping[score.ExitedInitiationLine[0]] - breakdown.InitLineRobot2 = exitedInitLineMapping[score.ExitedInitiationLine[1]] - breakdown.InitLineRobot3 = exitedInitLineMapping[score.ExitedInitiationLine[2]] - breakdown.AutoCellsBottom = sumPowerCells(score.AutoCellsBottom[:]) - breakdown.AutoCellsOuter = sumPowerCells(score.AutoCellsOuter[:]) - breakdown.AutoCellsInner = sumPowerCells(score.AutoCellsInner[:]) - breakdown.TeleopCellsBottom = sumPowerCells(score.TeleopCellsBottom[:]) - breakdown.TeleopCellsOuter = sumPowerCells(score.TeleopCellsOuter[:]) - breakdown.TeleopCellsInner = sumPowerCells(score.TeleopCellsInner[:]) - breakdown.Stage1Activated = scoreSummary.StagesActivated[0] - breakdown.Stage2Activated = scoreSummary.StagesActivated[1] - breakdown.Stage3Activated = scoreSummary.StagesActivated[2] - breakdown.Stage3TargetColor = controlPanelColorMapping[score.PositionControlTargetColor] - breakdown.EndgameRobot1 = endgameMapping[score.EndgameStatuses[0]] - breakdown.EndgameRobot2 = endgameMapping[score.EndgameStatuses[1]] - breakdown.EndgameRobot3 = endgameMapping[score.EndgameStatuses[2]] - breakdown.EndgameRungIsLevel = rungIsLevelMapping[score.RungIsLevel] - for _, foul := range score.Fouls { - if foul.Rule() != nil && !foul.Rule().IsRankingPoint { - if foul.Rule().IsTechnical { - breakdown.TechFoulCount++ - } else { - breakdown.FoulCount++ - } - } - } - breakdown.AutoInitLinePoints = scoreSummary.InitiationLinePoints - breakdown.AutoCellPoints = scoreSummary.AutoPowerCellPoints - breakdown.AutoPoints = scoreSummary.AutoPoints - breakdown.TeleopCellPoints = scoreSummary.TeleopPowerCellPoints - breakdown.ControlPanelPoints = scoreSummary.ControlPanelPoints - breakdown.EndgamePoints = scoreSummary.EndgamePoints - breakdown.TeleopPoints = scoreSummary.TeleopPowerCellPoints + scoreSummary.ControlPanelPoints + - scoreSummary.EndgamePoints - breakdown.FoulPoints = scoreSummary.FoulPoints - breakdown.TotalPoints = scoreSummary.Score - breakdown.ShieldEnergizedRankingPoint = scoreSummary.ControlPanelRankingPoint - breakdown.ShieldOperationalRankingPoint = scoreSummary.EndgameRankingPoint - - 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 -} - // Uploads the awards to The Blue Alliance. func (client *TbaClient) PublishAwards(database *model.Database) error { awards, err := database.GetAllAwards() diff --git a/plc/armorblock_string.go b/plc/armorblock_string.go index 4efa98d..a1a7c0f 100644 --- a/plc/armorblock_string.go +++ b/plc/armorblock_string.go @@ -10,14 +10,12 @@ func _() { var x [1]struct{} _ = x[redDs-0] _ = x[blueDs-1] - _ = x[shieldGenerator-2] - _ = x[controlPanel-3] - _ = x[armorBlockCount-4] + _ = x[armorBlockCount-2] } -const _armorBlock_name = "redDsblueDsshieldGeneratorcontrolPanelarmorBlockCount" +const _armorBlock_name = "redDsblueDsarmorBlockCount" -var _armorBlock_index = [...]uint8{0, 5, 11, 26, 38, 53} +var _armorBlock_index = [...]uint8{0, 5, 11} func (i armorBlock) String() string { if i < 0 || i >= armorBlock(len(_armorBlock_index)-1) { diff --git a/plc/coil_string.go b/plc/coil_string.go index d349c32..424bf43 100644 --- a/plc/coil_string.go +++ b/plc/coil_string.go @@ -16,23 +16,12 @@ func _() { _ = x[stackLightBlue-5] _ = x[stackLightBuzzer-6] _ = x[fieldResetLight-7] - _ = x[powerPortMotors-8] - _ = x[redStage1Light-9] - _ = x[redStage2Light-10] - _ = x[redStage3Light-11] - _ = x[blueStage1Light-12] - _ = x[blueStage2Light-13] - _ = x[blueStage3Light-14] - _ = x[redTrussLight-15] - _ = x[blueTrussLight-16] - _ = x[redControlPanelLight-17] - _ = x[blueControlPanelLight-18] - _ = x[coilCount-19] + _ = x[coilCount-8] } -const _coil_name = "heartbeatmatchResetstackLightGreenstackLightOrangestackLightRedstackLightBluestackLightBuzzerfieldResetLightpowerPortMotorsredStage1LightredStage2LightredStage3LightblueStage1LightblueStage2LightblueStage3LightredTrussLightblueTrussLightredControlPanelLightblueControlPanelLightcoilCount" +const _coil_name = "heartbeatmatchResetstackLightGreenstackLightOrangestackLightRedstackLightBluestackLightBuzzerfieldResetLightcoilCount" -var _coil_index = [...]uint16{0, 9, 19, 34, 50, 63, 77, 93, 108, 123, 137, 151, 165, 180, 195, 210, 223, 237, 257, 278, 287} +var _coil_index = [...]uint16{0, 9, 19, 34, 50, 63, 77, 93, 108} func (i coil) String() string { if i < 0 || i >= coil(len(_coil_index)-1) { diff --git a/plc/input_string.go b/plc/input_string.go index e2d002e..9875d27 100644 --- a/plc/input_string.go +++ b/plc/input_string.go @@ -21,16 +21,12 @@ func _() { _ = x[blueConnected1-10] _ = x[blueConnected2-11] _ = x[blueConnected3-12] - _ = x[redRungIsLevel-13] - _ = x[blueRungIsLevel-14] - _ = x[redPowerPortJam-15] - _ = x[bluePowerPortJam-16] - _ = x[inputCount-17] + _ = x[inputCount-13] } -const _input_name = "fieldEstopredEstop1redEstop2redEstop3blueEstop1blueEstop2blueEstop3redConnected1redConnected2redConnected3blueConnected1blueConnected2blueConnected3redRungIsLevelblueRungIsLevelredPowerPortJambluePowerPortJaminputCount" +const _input_name = "fieldEstopredEstop1redEstop2redEstop3blueEstop1blueEstop2blueEstop3redConnected1redConnected2redConnected3blueConnected1blueConnected2blueConnected3inputCount" -var _input_index = [...]uint8{0, 10, 19, 28, 37, 47, 57, 67, 80, 93, 106, 120, 134, 148, 162, 177, 192, 208, 218} +var _input_index = [...]uint8{0, 10, 19, 28, 37, 47, 57, 67, 80, 93, 106, 120, 134, 148} func (i input) String() string { if i < 0 || i >= input(len(_input_index)-1) { diff --git a/plc/plc.go b/plc/plc.go index ec77361..521aad4 100644 --- a/plc/plc.go +++ b/plc/plc.go @@ -7,7 +7,6 @@ package plc import ( "fmt" - "github.com/Team254/cheesy-arena/game" "github.com/Team254/cheesy-arena/websocket" "github.com/goburrow/modbus" "log" @@ -54,10 +53,6 @@ const ( blueConnected1 blueConnected2 blueConnected3 - redRungIsLevel - blueRungIsLevel - redPowerPortJam - bluePowerPortJam inputCount ) @@ -66,26 +61,6 @@ type register int const ( fieldIoConnection register = iota - redPowerPortBottom - redPowerPortOuter - redPowerPortInner - bluePowerPortBottom - bluePowerPortOuter - bluePowerPortInner - redControlPanelRed - redControlPanelGreen - redControlPanelBlue - redControlPanelIntensity - blueControlPanelRed - blueControlPanelGreen - blueControlPanelBlue - blueControlPanelIntensity - redControlPanelColor - blueControlPanelColor - redControlPanelLastColor - blueControlPanelLastColor - redControlPanelSegments - blueControlPanelSegments registerCount ) @@ -101,17 +76,6 @@ const ( stackLightBlue stackLightBuzzer fieldResetLight - powerPortMotors - redStage1Light - redStage2Light - redStage3Light - blueStage1Light - blueStage2Light - blueStage3Light - redTrussLight - blueTrussLight - redControlPanelLight - blueControlPanelLight coilCount ) @@ -121,8 +85,6 @@ type armorBlock int const ( redDs armorBlock = iota blueDs - shieldGenerator - controlPanel armorBlockCount ) @@ -231,36 +193,6 @@ func (plc *Plc) GetEthernetConnected() ([3]bool, [3]bool) { } } -// Returns the total number of power cells scored since match start in each level of the red and blue power ports. -func (plc *Plc) GetPowerPorts() ([3]int, [3]int) { - return [3]int{ - int(plc.registers[redPowerPortBottom]), - int(plc.registers[redPowerPortOuter]), - int(plc.registers[redPowerPortInner]), - }, - [3]int{ - int(plc.registers[bluePowerPortBottom]), - int(plc.registers[bluePowerPortOuter]), - int(plc.registers[bluePowerPortInner]), - } -} - -// Returns whether each of the red and blue power ports are jammed. -func (plc *Plc) GetPowerPortJams() (bool, bool) { - return plc.inputs[redPowerPortJam], plc.inputs[bluePowerPortJam] -} - -// Returns the current color and number of segment transitions for each of the red and blue control panels. -func (plc *Plc) GetControlPanels() (game.ControlPanelColor, int, game.ControlPanelColor, int) { - return game.ControlPanelColor(plc.registers[redControlPanelColor]), int(plc.registers[redControlPanelSegments]), - game.ControlPanelColor(plc.registers[blueControlPanelColor]), int(plc.registers[blueControlPanelSegments]) -} - -// Returns whether each of the red and blue rungs is level. -func (plc *Plc) GetRungs() (bool, bool) { - return plc.inputs[redRungIsLevel], plc.inputs[blueRungIsLevel] -} - // Sets the on/off state of the stack lights on the scoring table. func (plc *Plc) SetStackLights(red, blue, orange, green bool) { plc.coils[stackLightRed] = red @@ -279,33 +211,6 @@ func (plc *Plc) SetFieldResetLight(state bool) { plc.coils[fieldResetLight] = state } -// Sets the on/off state of the agitator motors within each power port. -func (plc *Plc) SetPowerPortMotors(state bool) { - plc.coils[powerPortMotors] = state -} - -// Sets the on/off state of the lights mounted within the shield generator trussing. -func (plc *Plc) SetStageActivatedLights(red, blue [3]bool) { - plc.coils[redStage1Light] = red[0] - plc.coils[redStage2Light] = red[1] - plc.coils[redStage3Light] = red[2] - plc.coils[blueStage1Light] = blue[0] - plc.coils[blueStage2Light] = blue[1] - plc.coils[blueStage3Light] = blue[2] -} - -// Sets the on/off state of the red and blue alliance stack lights mounted to the control panel. -func (plc *Plc) SetControlPanelLights(red, blue bool) { - plc.coils[redControlPanelLight] = red - plc.coils[blueControlPanelLight] = blue -} - -// Sets the on/off state of the red and blue alliance stack lights mounted to the top of the shield generator. -func (plc *Plc) SetShieldGeneratorLights(red, blue bool) { - plc.coils[redTrussLight] = red - plc.coils[blueTrussLight] = blue -} - func (plc *Plc) GetCycleState(max, index, duration int) bool { return plc.cycleCounter/duration%max == index } diff --git a/plc/plc_test.go b/plc/plc_test.go index 56d96c9..9b1af50 100644 --- a/plc/plc_test.go +++ b/plc/plc_test.go @@ -39,27 +39,27 @@ func TestGetArmorBlockStatuses(t *testing.T) { var plc Plc plc.registers[fieldIoConnection] = 0 - assert.Equal(t, map[string]bool{"RedDs": false, "BlueDs": false, "ShieldGenerator": false, "ControlPanel": false}, + assert.Equal(t, map[string]bool{"RedDs": false, "BlueDs": false}, plc.GetArmorBlockStatuses()) plc.registers[fieldIoConnection] = 1 - assert.Equal(t, map[string]bool{"RedDs": true, "BlueDs": false, "ShieldGenerator": false, "ControlPanel": false}, + assert.Equal(t, map[string]bool{"RedDs": true, "BlueDs": false}, plc.GetArmorBlockStatuses()) plc.registers[fieldIoConnection] = 2 - assert.Equal(t, map[string]bool{"RedDs": false, "BlueDs": true, "ShieldGenerator": false, "ControlPanel": false}, + assert.Equal(t, map[string]bool{"RedDs": false, "BlueDs": true}, plc.GetArmorBlockStatuses()) plc.registers[fieldIoConnection] = 4 - assert.Equal(t, map[string]bool{"RedDs": false, "BlueDs": false, "ShieldGenerator": true, "ControlPanel": false}, + assert.Equal(t, map[string]bool{"RedDs": false, "BlueDs": false}, plc.GetArmorBlockStatuses()) plc.registers[fieldIoConnection] = 8 - assert.Equal(t, map[string]bool{"RedDs": false, "BlueDs": false, "ShieldGenerator": false, "ControlPanel": true}, + assert.Equal(t, map[string]bool{"RedDs": false, "BlueDs": false}, plc.GetArmorBlockStatuses()) plc.registers[fieldIoConnection] = 5 - assert.Equal(t, map[string]bool{"RedDs": true, "BlueDs": false, "ShieldGenerator": true, "ControlPanel": false}, + assert.Equal(t, map[string]bool{"RedDs": true, "BlueDs": false}, plc.GetArmorBlockStatuses()) plc.registers[fieldIoConnection] = 10 - assert.Equal(t, map[string]bool{"RedDs": false, "BlueDs": true, "ShieldGenerator": false, "ControlPanel": true}, + assert.Equal(t, map[string]bool{"RedDs": false, "BlueDs": true}, plc.GetArmorBlockStatuses()) plc.registers[fieldIoConnection] = 15 - assert.Equal(t, map[string]bool{"RedDs": true, "BlueDs": true, "ShieldGenerator": true, "ControlPanel": true}, + assert.Equal(t, map[string]bool{"RedDs": true, "BlueDs": true}, plc.GetArmorBlockStatuses()) } diff --git a/plc/register_string.go b/plc/register_string.go index 8bf6c0a..1a26ba3 100644 --- a/plc/register_string.go +++ b/plc/register_string.go @@ -9,32 +9,12 @@ func _() { // Re-run the stringer command to generate them again. var x [1]struct{} _ = x[fieldIoConnection-0] - _ = x[redPowerPortBottom-1] - _ = x[redPowerPortOuter-2] - _ = x[redPowerPortInner-3] - _ = x[bluePowerPortBottom-4] - _ = x[bluePowerPortOuter-5] - _ = x[bluePowerPortInner-6] - _ = x[redControlPanelRed-7] - _ = x[redControlPanelGreen-8] - _ = x[redControlPanelBlue-9] - _ = x[redControlPanelIntensity-10] - _ = x[blueControlPanelRed-11] - _ = x[blueControlPanelGreen-12] - _ = x[blueControlPanelBlue-13] - _ = x[blueControlPanelIntensity-14] - _ = x[redControlPanelColor-15] - _ = x[blueControlPanelColor-16] - _ = x[redControlPanelLastColor-17] - _ = x[blueControlPanelLastColor-18] - _ = x[redControlPanelSegments-19] - _ = x[blueControlPanelSegments-20] - _ = x[registerCount-21] + _ = x[registerCount-1] } -const _register_name = "fieldIoConnectionredPowerPortBottomredPowerPortOuterredPowerPortInnerbluePowerPortBottombluePowerPortOuterbluePowerPortInnerredControlPanelRedredControlPanelGreenredControlPanelBlueredControlPanelIntensityblueControlPanelRedblueControlPanelGreenblueControlPanelBlueblueControlPanelIntensityredControlPanelColorblueControlPanelColorredControlPanelLastColorblueControlPanelLastColorredControlPanelSegmentsblueControlPanelSegmentsregisterCount" +const _register_name = "fieldIoConnectionregisterCount" -var _register_index = [...]uint16{0, 17, 35, 52, 69, 88, 106, 124, 142, 162, 181, 205, 224, 245, 265, 290, 310, 331, 355, 380, 403, 427, 440} +var _register_index = [...]uint16{0, 17} func (i register) String() string { if i < 0 || i >= register(len(_register_index)-1) { diff --git a/static/js/match_play.js b/static/js/match_play.js old mode 100644 new mode 100755 index b4d874e..d31fd1a --- a/static/js/match_play.js +++ b/static/js/match_play.js @@ -5,7 +5,6 @@ var websocket; var currentMatchId; -var scoreIsReady; var lowBatteryThreshold = 8; // Sends a websocket message to load a team into an alliance station. @@ -59,11 +58,22 @@ var startTimeout = function() { websocket.send("startTimeout", durationSec); }; +// Sends a websocket message to update the realtime score +var updateRealtimeScore = function() { + websocket.send("updateRealtimeScore", { + blueAuto: parseInt($("#blueAutoScore").val()), + redAuto: parseInt($("#redAutoScore").val()), + blueTeleop: parseInt($("#blueTeleopScore").val()), + redTeleop: parseInt($("#redTeleopScore").val()), + blueEndgame: parseInt($("#blueEndgameScore").val()), + redEndgame: parseInt($("#redEndgameScore").val()) + }) +}; + var confirmCommit = function(isReplay) { - if (isReplay || !scoreIsReady) { + if (isReplay) { // Show the appropriate message(s) in the confirmation dialog. $("#confirmCommitReplay").css("display", isReplay ? "block" : "none"); - $("#confirmCommitNotReady").css("display", scoreIsReady ? "none" : "block"); $("#confirmCommitResults").modal("show"); } else { commitResults(); @@ -140,6 +150,18 @@ var handleArenaStatus = function(data) { $("#discardResults").prop("disabled", true); $("#editResults").prop("disabled", true); $("#startTimeout").prop("disabled", false); + $("#blueAutoScore").val("0"); + $("#redAutoScore").val("0"); + $("#blueTeleopScore").val("0"); + $("#redTeleopScore").val("0"); + $("#blueEndgameScore").val("0"); + $("#redEndgameScore").val("0"); + $("#blueAutoScore").prop("disabled", true); + $("#redAutoScore").prop("disabled", true); + $("#blueTeleopScore").prop("disabled", true); + $("#redTeleopScore").prop("disabled", true); + $("#blueEndgameScore").prop("disabled", true); + $("#redEndgameScore").prop("disabled", true); break; case "START_MATCH": case "WARMUP_PERIOD": @@ -152,6 +174,12 @@ var handleArenaStatus = function(data) { $("#discardResults").prop("disabled", true); $("#editResults").prop("disabled", true); $("#startTimeout").prop("disabled", true); + $("#blueAutoScore").prop("disabled", false); + $("#redAutoScore").prop("disabled", false); + $("#blueTeleopScore").prop("disabled", false); + $("#redTeleopScore").prop("disabled", false); + $("#blueEndgameScore").prop("disabled", false); + $("#redEndgameScore").prop("disabled", false); break; case "POST_MATCH": $("#startMatch").prop("disabled", true); @@ -160,6 +188,12 @@ var handleArenaStatus = function(data) { $("#discardResults").prop("disabled", false); $("#editResults").prop("disabled", false); $("#startTimeout").prop("disabled", true); + $("#blueAutoScore").prop("disabled", false); + $("#redAutoScore").prop("disabled", false); + $("#blueTeleopScore").prop("disabled", false); + $("#redTeleopScore").prop("disabled", false); + $("#blueEndgameScore").prop("disabled", false); + $("#redEndgameScore").prop("disabled", false); break; case "TIMEOUT_ACTIVE": $("#startMatch").prop("disabled", true); @@ -168,6 +202,12 @@ var handleArenaStatus = function(data) { $("#discardResults").prop("disabled", true); $("#editResults").prop("disabled", true); $("#startTimeout").prop("disabled", true); + $("#blueAutoScore").prop("disabled", false); + $("#redAutoScore").prop("disabled", false); + $("#blueTeleopScore").prop("disabled", false); + $("#redTeleopScore").prop("disabled", false); + $("#blueEndgameScore").prop("disabled", false); + $("#redEndgameScore").prop("disabled", false); break; case "POST_TIMEOUT": $("#startMatch").prop("disabled", true); @@ -176,6 +216,12 @@ var handleArenaStatus = function(data) { $("#discardResults").prop("disabled", true); $("#editResults").prop("disabled", true); $("#startTimeout").prop("disabled", true); + $("#blueAutoScore").prop("disabled", false); + $("#redAutoScore").prop("disabled", false); + $("#blueTeleopScore").prop("disabled", false); + $("#redTeleopScore").prop("disabled", false); + $("#blueEndgameScore").prop("disabled", false); + $("#redEndgameScore").prop("disabled", false); break; } @@ -212,16 +258,6 @@ var handleAudienceDisplayMode = function(data) { $("input[name=audienceDisplay][value=" + data + "]").prop("checked", true); }; -// Handles a websocket message to signal whether the referee and scorers have committed after the match. -var handleScoringStatus = function(data) { - scoreIsReady = data.RefereeScoreReady && data.RedScoreReady && data.BlueScoreReady; - $("#refereeScoreStatus").attr("data-ready", data.RefereeScoreReady); - $("#redScoreStatus").text("Red Scoring " + data.NumRedScoringPanelsReady + "/" + data.NumRedScoringPanels); - $("#redScoreStatus").attr("data-ready", data.RedScoreReady); - $("#blueScoreStatus").text("Blue Scoring " + data.NumBlueScoringPanelsReady + "/" + data.NumBlueScoringPanels); - $("#blueScoreStatus").attr("data-ready", data.BlueScoreReady); -}; - // Handles a websocket message to update the alliance station display screen selector. var handleAllianceStationDisplayMode = function(data) { $("input[name=allianceStationDisplay]:checked").prop("checked", false); @@ -251,6 +287,5 @@ $(function() { matchTime: function(event) { handleMatchTime(event.data); }, matchTiming: function(event) { handleMatchTiming(event.data); }, realtimeScore: function(event) { handleRealtimeScore(event.data); }, - scoringStatus: function(event) { handleScoringStatus(event.data); }, }); }); diff --git a/static/js/match_review.js b/static/js/match_review.js index f770457..c176c9d 100644 --- a/static/js/match_review.js +++ b/static/js/match_review.js @@ -13,14 +13,10 @@ $("form").submit(function() { var redScoreJson = JSON.stringify(allianceResults["red"].score); var blueScoreJson = JSON.stringify(allianceResults["blue"].score); - var redCardsJson = JSON.stringify(allianceResults["red"].cards); - var blueCardsJson = JSON.stringify(allianceResults["blue"].cards); // Inject the JSON data into the form as hidden inputs. $("").attr("type", "hidden").attr("name", "redScoreJson").attr("value", redScoreJson).appendTo("form"); $("").attr("type", "hidden").attr("name", "blueScoreJson").attr("value", blueScoreJson).appendTo("form"); - $("").attr("type", "hidden").attr("name", "redCardsJson").attr("value", redCardsJson).appendTo("form"); - $("").attr("type", "hidden").attr("name", "blueCardsJson").attr("value", blueCardsJson).appendTo("form"); return true; }); @@ -31,41 +27,9 @@ var renderResults = function(alliance) { var scoreContent = scoreTemplate(result); $("#" + alliance + "Score").html(scoreContent); - // Set the values of the form fields from the JSON results data. - for (var i = 0; i < 4; i++) { - var i1 = i + 1; - - if (i < 2) { - getInputElement(alliance, "AutoCellsBottom" + i1).val(result.score.AutoCellsBottom[i]); - getInputElement(alliance, "AutoCellsOuter" + i1).val(result.score.AutoCellsOuter[i]); - getInputElement(alliance, "AutoCellsInner" + i1).val(result.score.AutoCellsInner[i]); - } - - if (i < 3) { - getInputElement(alliance, "ExitedInitiationLine" + i1).prop("checked", result.score.ExitedInitiationLine[i]); - getInputElement(alliance, "EndgameStatuses" + i1, result.score.EndgameStatuses[i]).prop("checked", true); - } - - getInputElement(alliance, "TeleopCellsBottom" + i1).val(result.score.TeleopCellsBottom[i]); - getInputElement(alliance, "TeleopCellsOuter" + i1).val(result.score.TeleopCellsOuter[i]); - getInputElement(alliance, "TeleopCellsInner" + i1).val(result.score.TeleopCellsInner[i]); - } - getInputElement(alliance, "ControlPanelStatus", result.score.ControlPanelStatus).prop("checked", true); - getInputElement(alliance, "RungIsLevel").prop("checked", result.score.RungIsLevel); - - if (result.score.Fouls != null) { - $.each(result.score.Fouls, function(k, v) { - getInputElement(alliance, "Foul" + k + "Team", v.TeamId).prop("checked", true); - getSelectElement(alliance, "Foul" + k + "RuleId").val(v.RuleId); - getInputElement(alliance, "Foul" + k + "Time").val(v.TimeInMatchSec); - }); - } - - if (result.cards != null) { - $.each(result.cards, function(k, v) { - getInputElement(alliance, "Team" + k + "Card", v).prop("checked", true); - }); - } + getInputElement(alliance, "AutoPoints").val(result.score.AutoPoints); + getInputElement(alliance, "TeleopPoints").val(result.score.TeleopPoints); + getInputElement(alliance, "EndgamePoints").val(result.score.EndgamePoints); }; // Converts the current form values back into JSON structures and caches them. @@ -76,63 +40,9 @@ var updateResults = function(alliance) { formData[v.name] = v.value; }); - result.score.ExitedInitiationLine = []; - result.score.AutoCellsBottom = []; - result.score.AutoCellsOuter = []; - result.score.AutoCellsInner = []; - result.score.TeleopCellsBottom = []; - result.score.TeleopCellsOuter = []; - result.score.TeleopCellsInner = []; - result.score.EndgameStatuses = []; - for (var i = 0; i < 4; i++) { - var i1 = i + 1; - - if (i < 2) { - result.score.AutoCellsBottom[i] = parseInt(formData[alliance + "AutoCellsBottom" + i1]); - result.score.AutoCellsOuter[i] = parseInt(formData[alliance + "AutoCellsOuter" + i1]); - result.score.AutoCellsInner[i] = parseInt(formData[alliance + "AutoCellsInner" + i1]); - } - - if (i < 3) { - result.score.ExitedInitiationLine[i] = formData[alliance + "ExitedInitiationLine" + i1] === "on"; - result.score.EndgameStatuses[i] = parseInt(formData[alliance + "EndgameStatuses" + i1]); - } - - result.score.TeleopCellsBottom[i] = parseInt(formData[alliance + "TeleopCellsBottom" + i1]); - result.score.TeleopCellsOuter[i] = parseInt(formData[alliance + "TeleopCellsOuter" + i1]); - result.score.TeleopCellsInner[i] = parseInt(formData[alliance + "TeleopCellsInner" + i1]); - } - result.score.ControlPanelStatus = parseInt(formData[alliance + "ControlPanelStatus"]); - result.score.RungIsLevel = formData[alliance + "RungIsLevel"] === "on"; - - result.score.Fouls = []; - for (var i = 0; formData[alliance + "Foul" + i + "Time"]; i++) { - var prefix = alliance + "Foul" + i; - var foul = {TeamId: parseInt(formData[prefix + "Team"]), RuleId: parseInt(formData[prefix + "RuleId"]), - TimeInMatchSec: parseFloat(formData[prefix + "Time"])}; - result.score.Fouls.push(foul); - } - - result.cards = {}; - $.each([result.team1, result.team2, result.team3], function(i, team) { - result.cards[team] = formData[alliance + "Team" + team + "Card"]; - }); -}; - -// Appends a blank foul to the end of the list. -var addFoul = function(alliance) { - updateResults(alliance); - var result = allianceResults[alliance]; - result.score.Fouls.push({TeamId: 0, Rule: "", TimeInMatchSec: 0}); - renderResults(alliance); -}; - -// Removes the given foul from the list. -var deleteFoul = function(alliance, index) { - updateResults(alliance); - var result = allianceResults[alliance]; - result.score.Fouls.splice(index, 1); - renderResults(alliance); + result.score.AutoPoints = parseInt(formData[alliance + "AutoPoints"]); + result.score.TeleopPoints = parseInt(formData[alliance + "TeleopPoints"]); + result.score.EndgamePoints = parseInt(formData[alliance + "EndgamePoints"]); }; // Returns the form input element having the given parameters. @@ -143,9 +53,3 @@ var getInputElement = function(alliance, name, value) { } return $(selector); }; - -// Returns the form select element having the given parameters. -var getSelectElement = function(alliance, name) { - var selector = "select[name=" + alliance + name + "]"; - return $(selector); -}; diff --git a/templates/base.html b/templates/base.html old mode 100644 new mode 100755 index ac47697..247ea83 --- a/templates/base.html +++ b/templates/base.html @@ -47,16 +47,6 @@
  • Alliance Selection
  • -