From 11b1b6a9432d730537b979a205ae0054a172d3f4 Mon Sep 17 00:00:00 2001 From: Patrick Fairbank Date: Sat, 18 Aug 2018 18:40:21 -0700 Subject: [PATCH] Update rules to match Chezy Champs changes and add tooltips containing rule descriptions. --- game/foul.go | 40 +++++++++++++++++++++++++++----- game/test_helpers.go | 3 ++- static/js/announcer_display.js | 3 +++ static/js/referee_display.js | 3 +++ templates/announcer_display.html | 2 +- templates/referee_display.html | 4 +++- web/announcer_display.go | 16 ++++++++++++- 7 files changed, 61 insertions(+), 10 deletions(-) diff --git a/game/foul.go b/game/foul.go index eb16686..d1f0196 100644 --- a/game/foul.go +++ b/game/foul.go @@ -14,15 +14,43 @@ type Foul struct { type Rule struct { RuleNumber string IsTechnical bool + Description string } // All rules from the 2018 game that carry point penalties. -var Rules = []Rule{{"S06", false}, {"C07", false}, {"C07", true}, {"G05", false}, {"G07", false}, - {"G09", true}, {"G10", false}, {"G11", false}, {"G13", false}, {"G14", false}, {"G15", false}, - {"G16", true}, {"G17", true}, {"G19", false}, {"G20", true}, {"G21", false}, {"G22", false}, - {"G23", false}, {"G24", true}, {"G25", false}, {"G25", true}, {"A01", false}, {"A02", false}, - {"A03", false}, {"A04", false}, {"A04", true}, {"A05", false}, {"H06", false}, {"H11", true}, - {"H12", true}, {"H13", false}, {"H14", false}} +var Rules = []Rule{ + {"S06", false, "DRIVE TEAMS may not extend any body part into the RETURN chute, the PORTAL chute, or the EXCHANGE tunnel."}, + {"C07", 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."}, + {"C07", true, "Strategies clearly aimed at forcing the opposing ALLIANCE to violate a rule are not in the spirit of FIRST® Robotics Competition and not allowed."}, + {"G05", false, "ROBOTS may not extend more than 16 in (41 cm). beyond their FRAME PERIMETER."}, + {"G07", false, "ROBOTS must be in compliance with BUMPER rules throughout the MATCH."}, + {"G10", false, "Strategies aimed at the destruction or inhibition of ROBOTS via attachment, damage, tipping, or entanglements are not allowed."}, + {"G11", false, "Initiating deliberate or damaging contact with an opponent ROBOT on or inside the vertical extension of its FRAME PERIMETER, including transitively through a POWER CUBE, is not allowed."}, + {"G13", false, "Fallen (i.e. tipped over) ROBOTS attempting to right themselves (either by themselves or with assistance from a partner ROBOT) have one ten (10) second grace period in which they may not be contacted by an opponent ROBOT."}, + {"G14", false, "ROBOTS may not pin an opponent’s ROBOT for more than five (5) seconds."}, + {"G15", false, "A ROBOT may not block their opponent’s EXCHANGE ZONE for more than five (5) seconds."}, + {"G16", true, "A ROBOT whose BUMPERS are breaking the plane of or completely contained by its NULL TERRITORY and not breaking the plane of the opponent’s PLATFORM ZONE may not be contacted by an opposing ROBOT either directly or transitively through a POWER CUBE, regardless of who initiates the contact."}, + {"G17", true, "Unless during the ENDGAME, or attempting to right a fallen (i.e. tipped over) ALLIANCE partner, ROBOTS may neither fully nor partially strategically support the weight of partner ROBOTS."}, + {"G19", false, "DRIVE TEAMS, ROBOTS, and OPERATOR CONSOLES are prohibited from the following actions with regards to interaction with ARCADE elements: grabbing, grasping, attaching to, hanging, deforming, becoming entangled, and damaging."}, + {"G20", true, "With the exception of placing a POWER CUBES on PLATES, ROBOTS may not deliberately use POWER CUBES in an attempt to ease or amplify the challenge associated with FIELD elements."}, + {"G21", false, "With the exception of feeding POWER CUBES through the lower opening of the EXCHANGE, ROBOTS may not intentionally eject POWER CUBES from the FIELD."}, + {"G22", false, "ROBOTS may not control more than one (1) POWER CUBE at a time, except when breaking the plane of their own EXCHANGE ZONE."}, + {"G23", false, "ROBOTS may not remove POWER CUBES, or cause POWER CUBES to be removed, from the opponent’s POWER CUBE ZONE."}, + {"G24", true, "Strategies aimed at removing POWER CUBES from PLATES are prohibited."}, + {"G25", false, "Except via the weight of placed POWER CUBES, ROBOTS may not directly or transitively cause or prevent the movement of PLATES to their ALLIANCE's advantage."}, + {"G25", true, "Except via the weight of placed POWER CUBES, ROBOTS may not directly or transitively cause or prevent the movement of PLATES to their ALLIANCE's advantage."}, + {"A01", false, "During AUTO, DRIVE TEAM members in ALLIANCE STATIONS and PORTALS may not contact anything in front of the STARTING LINES, unless for personal or equipment safety."}, + {"A02", 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 for ROBOT safety."}, + {"A03", false, "During AUTO, any control devices worn or held by the DRIVERS and/or HUMAN PLAYERS must be disconnected from the OPERATOR CONSOLE."}, + {"A04", false, "During AUTO, no part of a ROBOT’S BUMPERS may pass from the NULL TERRITORY to the opponent’s side of the FIELD."}, + {"A04", true, "During AUTO, no part of a ROBOT’S BUMPERS may pass from the NULL TERRITORY to the opponent’s side of the FIELD."}, + {"A05", false, "During AUTO, DRIVE TEAMS may not contact any POWER CUBES, unless for personal safety."}, + {"H06", false, "DRIVE TEAM members may not contact anything outside the zone in which they started the MATCH (e.g. the ALLIANCE STATION, PORTAL, designated area for the TECHNICIAN) during the MATCH."}, + {"H11", true, "During a MATCH, COACHES may not touch POWER CUBES unless for safety purposes."}, + {"H12", true, "During a MATCH, COACHES may not touch any component of the VAULT (including the buttons) unless for safety purposes."}, + {"H13", false, "DRIVE TEAMS may only deliberately cause POWER CUBES to leave an ALLIANCE STATION or PORTAL during TELEOP, by a HUMAN PLAYER or DRIVER, and through a PORTAL wall or the RETURN."}, + {"H14", false, "POWER CUBES may not be removed from the VAULT."}, +} func (foul *Foul) PointValue() int { if foul.IsTechnical { diff --git a/game/test_helpers.go b/game/test_helpers.go index 5edc255..a6a5784 100644 --- a/game/test_helpers.go +++ b/game/test_helpers.go @@ -6,7 +6,8 @@ package game func TestScore1() *Score { - fouls := []Foul{{Rule{"G22", false}, 25, 25.2}, {Rule{"G18", true}, 25, 150}, {Rule{"G20", true}, 1868, 0}} + fouls := []Foul{{Rule{"G22", false, ""}, 25, 25.2}, {Rule{"G18", true, ""}, 25, 150}, + {Rule{"G20", true, ""}, 1868, 0}} return &Score{1, 12, true, 47, 0, false, 3, true, 0, false, 2, 0, fouls, false} } diff --git a/static/js/announcer_display.js b/static/js/announcer_display.js index 5813ee7..95c5001 100644 --- a/static/js/announcer_display.js +++ b/static/js/announcer_display.js @@ -56,6 +56,9 @@ var handleSetFinalScore = function(data) { $("#blueScoreDetails").html(matchResultTemplate({score: data.BlueScoreSummary, fouls: data.BlueFouls, cards: data.BlueCards})); $("#matchResult").modal("show"); + + // Activate tooltips above the foul listings. + $("[data-toggle=tooltip]").tooltip({"placement": "top"}); }; var postMatchResult = function(data) { diff --git a/static/js/referee_display.js b/static/js/referee_display.js index ab0b7c1..0843d60 100644 --- a/static/js/referee_display.js +++ b/static/js/referee_display.js @@ -95,6 +95,9 @@ var commitMatch = function() { }; $(function() { + // Activate tooltips above the rule buttons. + $("[data-toggle=tooltip]").tooltip({"placement": "top"}); + // Set up the websocket back to the server. websocket = new CheesyWebsocket("/displays/referee/websocket", { }); diff --git a/templates/announcer_display.html b/templates/announcer_display.html index a2f8255..0d9d47e 100644 --- a/templates/announcer_display.html +++ b/templates/announcer_display.html @@ -98,7 +98,7 @@
{{"{{#if IsTechnical}}"}}Tech {{"{{/if}}"}}Foul
Team {{"{{TeamId}}"}}
-
{{"{{RuleNumber}}"}}
+
{{"{{RuleNumber}}"}}
{{"{{/each}}"}}

Cards

diff --git a/templates/referee_display.html b/templates/referee_display.html index 98be4c6..1489b29 100644 --- a/templates/referee_display.html +++ b/templates/referee_display.html @@ -60,7 +60,8 @@
{{range $rule := .Rules}} + data-rule="{{$rule.RuleNumber}}" data-is-technical="{{$rule.IsTechnical}}" + onclick="setFoulRule(this);" data-toggle="tooltip" title="{{$rule.Description}}"> {{$rule.RuleNumber}}{{if $rule.IsTechnical}}T{{end}} {{end}} @@ -94,6 +95,7 @@ + diff --git a/web/announcer_display.go b/web/announcer_display.go index 37ea27a..c141c5e 100644 --- a/web/announcer_display.go +++ b/web/announcer_display.go @@ -156,7 +156,8 @@ func (web *Web) announcerDisplayWebsocketHandler(w http.ResponseWriter, r *http. BlueCards map[string]string }{web.arena.SavedMatch.CapitalizedType(), web.arena.SavedMatch.DisplayName, web.arena.SavedMatchResult.RedScoreSummary(), web.arena.SavedMatchResult.BlueScoreSummary(), - web.arena.SavedMatchResult.RedScore.Fouls, web.arena.SavedMatchResult.BlueScore.Fouls, + populateFoulDescriptions(web.arena.SavedMatchResult.RedScore.Fouls), + populateFoulDescriptions(web.arena.SavedMatchResult.BlueScore.Fouls), web.arena.SavedMatchResult.RedCards, web.arena.SavedMatchResult.BlueCards} case _, ok := <-audienceDisplayListener: if !ok { @@ -206,3 +207,16 @@ func (web *Web) announcerDisplayWebsocketHandler(w http.ResponseWriter, r *http. } } } + +// Copy the description from the rules to the fouls so that they are available to the announcer. +func populateFoulDescriptions(fouls []game.Foul) []game.Foul { + for i := range fouls { + for _, rule := range game.Rules { + if fouls[i].RuleNumber == rule.RuleNumber { + fouls[i].Description = rule.Description + break + } + } + } + return fouls +}