Skip to content

Commit

Permalink
Implement alternate microphone scoring for Sunset Showdown.
Browse files Browse the repository at this point in the history
  • Loading branch information
patfair committed Jun 21, 2024
1 parent 0c845c6 commit 4278439
Show file tree
Hide file tree
Showing 12 changed files with 90 additions and 62 deletions.
23 changes: 11 additions & 12 deletions game/score.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
package game

type Score struct {
LeaveStatuses [3]bool
AmpSpeaker AmpSpeaker
EndgameStatuses [3]EndgameStatus
MicrophoneStatuses [3]bool
TrapStatuses [3]bool
Fouls []Foul
PlayoffDq bool
LeaveStatuses [3]bool
AmpSpeaker AmpSpeaker
EndgameStatuses [3]EndgameStatus
MicrophoneCounts [3]int
TrapStatuses [3]bool
Fouls []Foul
PlayoffDq bool
}

// Game-specific constants that cannot be changed by the user.
Expand Down Expand Up @@ -99,10 +99,9 @@ func (score *Score) Summarize(opponentScore *Score) *ScoreSummary {
summary.HarmonyPoints += 2 * (onstageRobots - 1)
}

// Handle microphones.
if score.MicrophoneStatuses[i] && onstageRobots > 0 {
summary.SpotlightPoints += onstageRobots
}
// Handle microphones. Special logic for Sunset Showdown: multiple notes are counted for one point each and
// there's no ONSTAGE requirement.
summary.SpotlightPoints += score.MicrophoneCounts[i]

// Handle traps.
if score.TrapStatuses[i] {
Expand Down Expand Up @@ -166,7 +165,7 @@ func (score *Score) Equals(other *Score) bool {
if score.LeaveStatuses != other.LeaveStatuses ||
score.AmpSpeaker != other.AmpSpeaker ||
score.EndgameStatuses != other.EndgameStatuses ||
score.MicrophoneStatuses != other.MicrophoneStatuses ||
score.MicrophoneCounts != other.MicrophoneCounts ||
score.TrapStatuses != other.TrapStatuses ||
score.PlayoffDq != other.PlayoffDq ||
len(score.Fouls) != len(other.Fouls) {
Expand Down
26 changes: 13 additions & 13 deletions game/score_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ func TestScoreSummary(t *testing.T) {
assert.Equal(t, 36, redSummary.AutoPoints)
assert.Equal(t, 6, redSummary.AmpPoints)
assert.Equal(t, 57, redSummary.SpeakerPoints)
assert.Equal(t, 14, redSummary.StagePoints)
assert.Equal(t, 81, redSummary.MatchPoints)
assert.Equal(t, 20, redSummary.StagePoints)
assert.Equal(t, 87, redSummary.MatchPoints)
assert.Equal(t, 0, redSummary.FoulPoints)
assert.Equal(t, 81, redSummary.Score)
assert.Equal(t, 87, redSummary.Score)
assert.Equal(t, true, redSummary.CoopertitionCriteriaMet)
assert.Equal(t, false, redSummary.CoopertitionBonus)
assert.Equal(t, 17, redSummary.NumNotes)
Expand All @@ -37,10 +37,10 @@ func TestScoreSummary(t *testing.T) {
assert.Equal(t, 42, blueSummary.AutoPoints)
assert.Equal(t, 51, blueSummary.AmpPoints)
assert.Equal(t, 161, blueSummary.SpeakerPoints)
assert.Equal(t, 13, blueSummary.StagePoints)
assert.Equal(t, 227, blueSummary.MatchPoints) // 187
assert.Equal(t, 14, blueSummary.StagePoints)
assert.Equal(t, 228, blueSummary.MatchPoints)
assert.Equal(t, 29, blueSummary.FoulPoints)
assert.Equal(t, 256, blueSummary.Score)
assert.Equal(t, 257, blueSummary.Score)
assert.Equal(t, false, blueSummary.CoopertitionCriteriaMet)
assert.Equal(t, false, blueSummary.CoopertitionBonus)
assert.Equal(t, 85, blueSummary.NumNotes)
Expand Down Expand Up @@ -163,7 +163,7 @@ func TestScoreEnsembleBonusRankingPoint(t *testing.T) {
var score Score

score.EndgameStatuses = [3]EndgameStatus{EndgameNone, EndgameNone, EndgameNone}
score.MicrophoneStatuses = [3]bool{false, false, false}
score.MicrophoneCounts = [3]int{0, 0, 0}
score.TrapStatuses = [3]bool{false, false, false}
assert.Equal(t, false, score.Summarize(&Score{}).EnsembleBonusRankingPoint)

Expand All @@ -186,24 +186,24 @@ func TestScoreEnsembleBonusRankingPoint(t *testing.T) {

// Try various combinations with microphones.
score.EndgameStatuses = [3]EndgameStatus{EndgameStageLeft, EndgameCenterStage, EndgameStageRight}
score.MicrophoneStatuses = [3]bool{true, false, false}
score.MicrophoneCounts = [3]int{1, 0, 0}
assert.Equal(t, 10, score.Summarize(&Score{}).StagePoints)
assert.Equal(t, true, score.Summarize(&Score{}).EnsembleBonusRankingPoint)
score.MicrophoneStatuses = [3]bool{true, true, true}
score.MicrophoneCounts = [3]int{1, 1, 1}
assert.Equal(t, 12, score.Summarize(&Score{}).StagePoints)
assert.Equal(t, true, score.Summarize(&Score{}).EnsembleBonusRankingPoint)
score.EndgameStatuses = [3]EndgameStatus{EndgameNone, EndgameStageRight, EndgameStageRight}
score.MicrophoneStatuses = [3]bool{false, false, true}
score.MicrophoneCounts = [3]int{0, 0, 2}
assert.Equal(t, 10, score.Summarize(&Score{}).StagePoints)
assert.Equal(t, true, score.Summarize(&Score{}).EnsembleBonusRankingPoint)
score.EndgameStatuses = [3]EndgameStatus{EndgameParked, EndgameStageRight, EndgameCenterStage}
score.MicrophoneStatuses = [3]bool{false, true, false}
score.MicrophoneCounts = [3]int{0, 1, 0}
assert.Equal(t, 8, score.Summarize(&Score{}).StagePoints)
assert.Equal(t, false, score.Summarize(&Score{}).EnsembleBonusRankingPoint)

// Try various combinations with traps.
score.EndgameStatuses = [3]EndgameStatus{EndgameStageLeft, EndgameCenterStage, EndgameParked}
score.MicrophoneStatuses = [3]bool{false, false, false}
score.MicrophoneCounts = [3]int{0, 0, 0}
score.TrapStatuses = [3]bool{false, false, true}
assert.Equal(t, 12, score.Summarize(&Score{}).StagePoints)
assert.Equal(t, true, score.Summarize(&Score{}).EnsembleBonusRankingPoint)
Expand Down Expand Up @@ -261,7 +261,7 @@ func TestScoreEquals(t *testing.T) {
assert.False(t, score2.Equals(score1))

score2 = TestScore1()
score2.MicrophoneStatuses[0] = true
score2.MicrophoneCounts[0] = 7
assert.False(t, score1.Equals(score2))
assert.False(t, score2.Equals(score1))

Expand Down
20 changes: 10 additions & 10 deletions game/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@ func TestScore1() *Score {
TeleopUnamplifiedSpeakerNotes: 1,
TeleopAmplifiedSpeakerNotes: 5,
},
EndgameStatuses: [3]EndgameStatus{EndgameParked, EndgameNone, EndgameStageLeft},
MicrophoneStatuses: [3]bool{false, true, true},
TrapStatuses: [3]bool{true, true, false},
Fouls: fouls,
PlayoffDq: false,
EndgameStatuses: [3]EndgameStatus{EndgameParked, EndgameNone, EndgameStageLeft},
MicrophoneCounts: [3]int{1, 3, 2},
TrapStatuses: [3]bool{true, true, false},
Fouls: fouls,
PlayoffDq: false,
}
}

Expand All @@ -44,11 +44,11 @@ func TestScore2() *Score {
TeleopUnamplifiedSpeakerNotes: 3,
TeleopAmplifiedSpeakerNotes: 23,
},
EndgameStatuses: [3]EndgameStatus{EndgameStageLeft, EndgameCenterStage, EndgameCenterStage},
MicrophoneStatuses: [3]bool{false, true, true},
TrapStatuses: [3]bool{false, false, false},
Fouls: []Foul{},
PlayoffDq: false,
EndgameStatuses: [3]EndgameStatus{EndgameStageLeft, EndgameCenterStage, EndgameCenterStage},
MicrophoneCounts: [3]int{0, 2, 1},
TrapStatuses: [3]bool{false, false, false},
Fouls: []Foul{},
PlayoffDq: false,
}
}

Expand Down
6 changes: 3 additions & 3 deletions partner/tba.go
Original file line number Diff line number Diff line change
Expand Up @@ -659,9 +659,9 @@ func createTbaScoringBreakdown(
breakdown.EndGameParkPoints = scoreSummary.ParkPoints
breakdown.EndGameOnStagePoints = scoreSummary.OnStagePoints
breakdown.EndGameHarmonyPoints = scoreSummary.HarmonyPoints
breakdown.MicStageLeft = score.MicrophoneStatuses[0]
breakdown.MicCenterStage = score.MicrophoneStatuses[1]
breakdown.MicStageRight = score.MicrophoneStatuses[2]
breakdown.MicStageLeft = score.MicrophoneCounts[0] > 0
breakdown.MicCenterStage = score.MicrophoneCounts[1] > 0
breakdown.MicStageRight = score.MicrophoneCounts[2] > 0
breakdown.EndGameSpotLightBonusPoints = scoreSummary.SpotlightPoints
breakdown.TrapStageLeft = score.TrapStatuses[0]
breakdown.TrapCenterStage = score.TrapStatuses[1]
Expand Down
15 changes: 14 additions & 1 deletion static/css/scoring_panel.css
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ body {
flex-grow: 1;
height: 100%;
}
.stage-side-col div {
.stage-side-col>div {
display: flex;
justify-content: center;
align-items: center;
Expand All @@ -142,3 +142,16 @@ body {
left: 12.2vw;
width: 9vw;
}
.microphone {
width: 50%;
background-color: #263;
}
.microphone[data-value="0"] {
background-color: #333;
}
.microphone-counter>div {
width: 33.3%;
height: 100%;
border: none;
text-align: center;
}
6 changes: 3 additions & 3 deletions static/js/match_review.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const renderResults = function(alliance) {

getInputElement(alliance, "LeaveStatuses" + i1).prop("checked", result.score.LeaveStatuses[i]);
getInputElement(alliance, "EndgameStatuses" + i1, result.score.EndgameStatuses[i]).prop("checked", true);
getInputElement(alliance, "MicrophoneStatuses" + i1).prop("checked", result.score.MicrophoneStatuses[i]);
getInputElement(alliance, "MicrophoneCounts" + i1).val(result.score.MicrophoneCounts[i]);
getInputElement(alliance, "TrapStatuses" + i1).prop("checked", result.score.TrapStatuses[i]);
}

Expand Down Expand Up @@ -80,14 +80,14 @@ const updateResults = function(alliance) {
TeleopAmplifiedSpeakerNotes: parseInt(formData[alliance + "TeleopAmplifiedSpeakerNotes"]),
};
result.score.EndgameStatuses = [];
result.score.MicrophoneStatuses = [];
result.score.MicrophoneCounts = [];
result.score.TrapStatuses = [];
for (let i = 0; i < 3; i++) {
const i1 = i + 1;

result.score.LeaveStatuses[i] = formData[alliance + "LeaveStatuses" + i1] === "on";
result.score.EndgameStatuses[i] = parseInt(formData[alliance + "EndgameStatuses" + i1]);
result.score.MicrophoneStatuses[i] = formData[alliance + "MicrophoneStatuses" + i1] === "on";
result.score.MicrophoneCounts[i] = parseInt(formData[alliance + "MicrophoneCounts" + i1]);
result.score.TrapStatuses[i] = formData[alliance + "TrapStatuses" + i1] === "on";
}

Expand Down
3 changes: 2 additions & 1 deletion static/js/scoring_panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ const handleRealtimeScore = function(data) {
$(`#stageSide0Team${i1}`).attr("data-value", score.EndgameStatuses[i] === 2);
$(`#stageSide1Team${i1}`).attr("data-value", score.EndgameStatuses[i] === 3);
$(`#stageSide2Team${i1}`).attr("data-value", score.EndgameStatuses[i] === 4);
$(`#stageSide${i}Microphone`).attr("data-value", score.MicrophoneStatuses[i]);
$(`#stageSide${i}Microphone`).attr("data-value", score.MicrophoneCounts[i]);
$(`#stageSide${i}Microphone`).html(`Mic<br />${score.MicrophoneCounts[i]}`);
$(`#stageSide${i}Trap`).attr("data-value", score.TrapStatuses[i]);
}
};
Expand Down
24 changes: 15 additions & 9 deletions templates/edit_match_result.html
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,23 @@ <h6 class="fw-bold mb-2">Robots On Stage</h6>
</div>
<h6 class="fw-bold mb-2">High Notes on Microphones</h6>
<div class="row mb-3">
<div class="col-lg-2">
<label class="control-label">Stage Left</label>
<input type="checkbox" class="ms-3" name="{{"{{alliance}}"}}MicrophoneStatuses1">
<div class="col-lg-1 text-end">
<label class="control-label">Stage Left:</label>
</div>
<div class="col-lg-2">
<label class="control-label">Center Stage</label>
<input type="checkbox" class="ms-3" name="{{"{{alliance}}"}}MicrophoneStatuses2">
<div class="col-lg-1">
<input type="text" class="form-control input-sm" name="{{"{{alliance}}"}}MicrophoneCounts1">
</div>
<div class="col-lg-2">
<label class="control-label">Stage Right</label>
<input type="checkbox" class="ms-3" name="{{"{{alliance}}"}}MicrophoneStatuses3">
<div class="col-lg-2 text-end">
<label class="control-label">Center Stage:</label>
</div>
<div class="col-lg-1">
<input type="text" class="form-control input-sm" name="{{"{{alliance}}"}}MicrophoneCounts2">
</div>
<div class="col-lg-2 text-end">
<label class="control-label">Stage Right:</label>
</div>
<div class="col-lg-1">
<input type="text" class="form-control input-sm" name="{{"{{alliance}}"}}MicrophoneCounts3">
</div>
</div>
<h6 class="fw-bold mb-2">Notes in Traps</h6>
Expand Down
6 changes: 5 additions & 1 deletion templates/scoring_panel.html
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,11 @@
<div id="stageSide{{.index}}Team3" class="team-3 boolean" onclick="handleClick('onStage', 3, {{.index}});"></div>
</div>
<div class="stage-side-col">
<div id="stageSide{{.index}}Microphone" class="boolean" onclick="handleClick('microphone', 0, {{.index}});">Mic</div>
<div class="microphone-counter">
<div class="counter-minus" onclick="handleClick('microphoneDecrement', 0, {{.index}});">&ndash;</div>
<div class="microphone" id="stageSide{{.index}}Microphone"></div>
<div class="counter-plus" onclick="handleClick('microphoneIncrement', 0, {{.index}});">+</div>
</div>
<div id="stageSide{{.index}}Trap" class="boolean" onclick="handleClick('trap', 0, {{.index}});">Trap</div>
</div>
{{end}}
4 changes: 2 additions & 2 deletions web/match_review_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,8 @@ func TestMatchReviewEditExistingResult(t *testing.T) {
recorder := web.getHttpResponse("/match_review")
assert.Equal(t, 200, recorder.Code)
assert.Contains(t, recorder.Body.String(), ">QF4-3<")
assert.Contains(t, recorder.Body.String(), ">81<") // The red score
assert.Contains(t, recorder.Body.String(), ">256<") // The blue score
assert.Contains(t, recorder.Body.String(), ">87<") // The red score
assert.Contains(t, recorder.Body.String(), ">257<") // The blue score

// Check response for non-existent match.
recorder = web.getHttpResponse(fmt.Sprintf("/match_review/%d/edit", 12345))
Expand Down
9 changes: 7 additions & 2 deletions web/scoring_panel.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,14 @@ func (web *Web) scoringPanelWebsocketHandler(w http.ResponseWriter, r *http.Requ
}
scoreChanged = true
}
case "microphone":
case "microphoneIncrement":
if args.StageIndex >= 0 && args.StageIndex <= 2 {
score.MicrophoneStatuses[args.StageIndex] = !score.MicrophoneStatuses[args.StageIndex]
score.MicrophoneCounts[args.StageIndex] += 1
scoreChanged = true
}
case "microphoneDecrement":
if args.StageIndex >= 0 && args.StageIndex <= 2 && score.MicrophoneCounts[args.StageIndex] > 0 {
score.MicrophoneCounts[args.StageIndex] -= 1
scoreChanged = true
}
case "trap":
Expand Down
10 changes: 5 additions & 5 deletions web/scoring_panel_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func TestScoringPanelWebsocket(t *testing.T) {
scoringData.TeamPosition = 3
scoringData.StageIndex = 2
redWs.Write("onStage", scoringData)
redWs.Write("microphone", scoringData)
redWs.Write("microphoneIncrement", scoringData)
scoringData.StageIndex = 0
redWs.Write("trap", scoringData)
for i := 0; i < 5; i++ {
Expand All @@ -98,21 +98,21 @@ func TestScoringPanelWebsocket(t *testing.T) {
[3]game.EndgameStatus{game.EndgameStageLeft, game.EndgameCenterStage, game.EndgameNone},
web.arena.BlueRealtimeScore.CurrentScore.EndgameStatuses,
)
assert.Equal(t, [3]bool{false, false, false}, web.arena.BlueRealtimeScore.CurrentScore.MicrophoneStatuses)
assert.Equal(t, [3]int{0, 0, 0}, web.arena.BlueRealtimeScore.CurrentScore.MicrophoneCounts)
assert.Equal(t, [3]bool{false, false, false}, web.arena.BlueRealtimeScore.CurrentScore.TrapStatuses)
assert.Equal(
t,
[3]game.EndgameStatus{game.EndgameNone, game.EndgameNone, game.EndgameStageRight},
web.arena.RedRealtimeScore.CurrentScore.EndgameStatuses,
)
assert.Equal(t, [3]bool{false, false, true}, web.arena.RedRealtimeScore.CurrentScore.MicrophoneStatuses)
assert.Equal(t, [3]int{0, 0, 1}, web.arena.RedRealtimeScore.CurrentScore.MicrophoneCounts)
assert.Equal(t, [3]bool{true, false, false}, web.arena.RedRealtimeScore.CurrentScore.TrapStatuses)
scoringData.StageIndex = 1
redWs.Write("trap", scoringData)
scoringData.StageIndex = 0
redWs.Write("trap", scoringData)
scoringData.StageIndex = 2
redWs.Write("microphone", scoringData)
redWs.Write("microphoneIncrement", scoringData)
scoringData.TeamPosition = 1
blueWs.Write("park", scoringData)
scoringData.TeamPosition = 2
Expand All @@ -127,7 +127,7 @@ func TestScoringPanelWebsocket(t *testing.T) {
[3]game.EndgameStatus{game.EndgameParked, game.EndgameNone, game.EndgameNone},
web.arena.BlueRealtimeScore.CurrentScore.EndgameStatuses,
)
assert.Equal(t, [3]bool{false, false, false}, web.arena.RedRealtimeScore.CurrentScore.MicrophoneStatuses)
assert.Equal(t, [3]int{0, 0, 2}, web.arena.RedRealtimeScore.CurrentScore.MicrophoneCounts)
assert.Equal(t, [3]bool{false, true, false}, web.arena.RedRealtimeScore.CurrentScore.TrapStatuses)

// Test that some invalid commands do nothing and don't result in score change notifications.
Expand Down

0 comments on commit 4278439

Please sign in to comment.