10 Commits

Author SHA1 Message Date
Patrick Fairbank
a4bbf26b31 Fix formatting. 2023-02-05 13:35:38 -08:00
Patrick Fairbank
02cb9e4e41 Update double-elimination bracket to match 2023 rules. 2023-02-05 13:33:35 -08:00
Patrick Fairbank
e8c7d1103b Update to Go 1.20 and fix rand-related issues. 2023-02-05 13:32:42 -08:00
Patrick Fairbank
5ee07ee33f Update test GitHub Action to fail if gofmt makes changes. 2022-11-11 09:03:55 -08:00
Patrick Fairbank
349313c486 Fix test failure. 2022-09-29 19:07:36 -07:00
Patrick Fairbank
1165e71503 Switch standalone bracket display to highlight current match without connectors, rather than saved match with connectors. 2022-09-29 19:07:30 -07:00
Patrick Fairbank
9914768c1d Various UI tweaks. 2022-09-29 19:05:59 -07:00
Patrick Fairbank
ce9cb085cb Shrink match state text on queue display to fit. 2022-09-29 17:53:57 -07:00
Patrick Fairbank
642116bd62 Shrink team numbers on alliance display to fit iPads. 2022-09-22 06:38:28 -07:00
Patrick Fairbank
3d566f4866 Set display name when pushing double-elimination matches to TBA. 2022-09-11 13:01:50 -07:00
22 changed files with 227 additions and 200 deletions

View File

@@ -13,7 +13,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: 1.18.x
go-version: 1.20.x
- name: Check out code
uses: actions/checkout@v2

View File

@@ -7,7 +7,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v2
with:
go-version: 1.18.x
go-version: 1.20.x
- name: Check out code
uses: actions/checkout@v2
- name: Build
@@ -15,4 +15,4 @@ jobs:
- name: Test
run: go test ./...
- name: Check formatting
run: go fmt ./...
run: test -z "$(go fmt ./...)"

View File

@@ -34,15 +34,15 @@ var doubleEliminationBracketMatchupTemplates = []matchupTemplate{
matchupKey: newMatchupKey(1, 3),
displayName: "3",
NumWinsToAdvance: 1,
redAllianceSource: allianceSource{allianceId: 3},
blueAllianceSource: allianceSource{allianceId: 6},
redAllianceSource: allianceSource{allianceId: 2},
blueAllianceSource: allianceSource{allianceId: 7},
},
{
matchupKey: newMatchupKey(1, 4),
displayName: "4",
NumWinsToAdvance: 1,
redAllianceSource: allianceSource{allianceId: 2},
blueAllianceSource: allianceSource{allianceId: 7},
redAllianceSource: allianceSource{allianceId: 3},
blueAllianceSource: allianceSource{allianceId: 6},
},
{
matchupKey: newMatchupKey(2, 1),
@@ -90,28 +90,28 @@ var doubleEliminationBracketMatchupTemplates = []matchupTemplate{
matchupKey: newMatchupKey(4, 1),
displayName: "11",
NumWinsToAdvance: 1,
redAllianceSource: newWinnerAllianceSource(3, 2),
blueAllianceSource: newWinnerAllianceSource(3, 1),
redAllianceSource: newWinnerAllianceSource(2, 3),
blueAllianceSource: newWinnerAllianceSource(2, 4),
},
{
matchupKey: newMatchupKey(4, 2),
displayName: "12",
NumWinsToAdvance: 1,
redAllianceSource: newWinnerAllianceSource(2, 3),
blueAllianceSource: newWinnerAllianceSource(2, 4),
redAllianceSource: newWinnerAllianceSource(3, 2),
blueAllianceSource: newWinnerAllianceSource(3, 1),
},
{
matchupKey: newMatchupKey(5, 1),
displayName: "13",
NumWinsToAdvance: 1,
redAllianceSource: newLoserAllianceSource(4, 2),
blueAllianceSource: newWinnerAllianceSource(4, 1),
redAllianceSource: newLoserAllianceSource(4, 1),
blueAllianceSource: newWinnerAllianceSource(4, 2),
},
{
matchupKey: newMatchupKey(6, 1),
displayName: "F",
NumWinsToAdvance: 2,
redAllianceSource: newWinnerAllianceSource(4, 2),
redAllianceSource: newWinnerAllianceSource(4, 1),
blueAllianceSource: newWinnerAllianceSource(5, 1),
},
}

View File

@@ -22,8 +22,8 @@ func TestDoubleEliminationInitial(t *testing.T) {
if assert.Equal(t, 4, len(matches)) {
assertMatch(t, matches[0], "1", 1, 8)
assertMatch(t, matches[1], "2", 4, 5)
assertMatch(t, matches[2], "3", 3, 6)
assertMatch(t, matches[3], "4", 2, 7)
assertMatch(t, matches[2], "3", 2, 7)
assertMatch(t, matches[3], "4", 3, 6)
}
}
@@ -65,21 +65,21 @@ func TestDoubleEliminationProgression(t *testing.T) {
assertMatch(t, matches[5], "7", 8, 4)
}
scoreMatch(database, "3", game.RedWonMatch)
scoreMatch(database, "3", game.BlueWonMatch)
assert.Nil(t, bracket.Update(database, &dummyStartTime))
matches, err = database.GetMatchesByType("elimination")
assert.Nil(t, err)
assert.Equal(t, 6, len(matches))
scoreMatch(database, "4", game.BlueWonMatch)
scoreMatch(database, "4", game.RedWonMatch)
assert.Nil(t, bracket.Update(database, &dummyStartTime))
matches, err = database.GetMatchesByType("elimination")
assert.Nil(t, err)
if assert.Equal(t, 8, len(matches)) {
assertMatch(t, matches[4], "5", 1, 5)
assertMatch(t, matches[5], "6", 6, 2)
assertMatch(t, matches[5], "6", 2, 6)
assertMatch(t, matches[6], "7", 8, 4)
assertMatch(t, matches[7], "8", 3, 7)
assertMatch(t, matches[7], "8", 7, 3)
}
scoreMatch(database, "5", game.BlueWonMatch)
@@ -88,7 +88,7 @@ func TestDoubleEliminationProgression(t *testing.T) {
assert.Nil(t, err)
assert.Equal(t, 8, len(matches))
scoreMatch(database, "6", game.BlueWonMatch)
scoreMatch(database, "6", game.RedWonMatch)
assert.Nil(t, bracket.Update(database, &dummyStartTime))
matches, err = database.GetMatchesByType("elimination")
assert.Nil(t, err)
@@ -102,13 +102,13 @@ func TestDoubleEliminationProgression(t *testing.T) {
assertMatch(t, matches[8], "9", 8, 2)
}
scoreMatch(database, "8", game.RedWonMatch)
scoreMatch(database, "8", game.BlueWonMatch)
assert.Nil(t, bracket.Update(database, &dummyStartTime))
matches, err = database.GetMatchesByType("elimination")
assert.Nil(t, err)
if assert.Equal(t, 11, len(matches)) {
assertMatch(t, matches[9], "10", 7, 5)
assertMatch(t, matches[10], "12", 4, 3)
assertMatch(t, matches[10], "11", 4, 3)
}
scoreMatch(database, "9", game.RedWonMatch)
@@ -122,8 +122,8 @@ func TestDoubleEliminationProgression(t *testing.T) {
matches, err = database.GetMatchesByType("elimination")
assert.Nil(t, err)
if assert.Equal(t, 12, len(matches)) {
assertMatch(t, matches[10], "11", 7, 8)
assertMatch(t, matches[11], "12", 4, 3)
assertMatch(t, matches[10], "11", 4, 3)
assertMatch(t, matches[11], "12", 7, 8)
}
scoreMatch(database, "11", game.RedWonMatch)

View File

@@ -17,7 +17,7 @@ func TestMatchupDisplayNames(t *testing.T) {
assert.Equal(t, "Finals", bracket.FinalsMatchup.LongDisplayName())
assert.Equal(t, "F-1", bracket.FinalsMatchup.matchDisplayName(1))
assert.Equal(t, "W 12", bracket.FinalsMatchup.RedAllianceSourceDisplayName())
assert.Equal(t, "W 11", bracket.FinalsMatchup.RedAllianceSourceDisplayName())
assert.Equal(t, "W 13", bracket.FinalsMatchup.BlueAllianceSourceDisplayName())
match13, err := bracket.GetMatchup(5, 1)
@@ -25,8 +25,8 @@ func TestMatchupDisplayNames(t *testing.T) {
assert.Equal(t, "Match 13", match13.LongDisplayName())
assert.Equal(t, "13", match13.matchDisplayName(1))
assert.Equal(t, "13-2", match13.matchDisplayName(2))
assert.Equal(t, "L 12", match13.RedAllianceSourceDisplayName())
assert.Equal(t, "W 11", match13.BlueAllianceSourceDisplayName())
assert.Equal(t, "L 11", match13.RedAllianceSourceDisplayName())
assert.Equal(t, "W 12", match13.BlueAllianceSourceDisplayName())
bracket, err = NewSingleEliminationBracket(8)
assert.Nil(t, err)

View File

@@ -1,14 +1,15 @@
// Copyright 2014 Team 254. All Rights Reserved.
// Author: pat@patfairbank.com (Patrick Fairbank)
// Go version 1.20 or newer is required due to how it initializes the PRNG.
//go:build go1.20
package main
import (
"github.com/Team254/cheesy-arena-lite/field"
"github.com/Team254/cheesy-arena-lite/web"
"log"
"math/rand"
"time"
)
const eventDbPath = "./event.db"
@@ -16,8 +17,6 @@ const httpPort = 8080
// Main entry point for the application.
func main() {
rand.Seed(time.Now().UnixNano())
arena, err := field.NewArena(eventDbPath)
if err != nil {
log.Fatalln("Error during startup: ", err)

View File

@@ -121,7 +121,7 @@ func (match *Match) IsComplete() bool {
}
func (match *Match) CapitalizedType() string {
if match.Type == "" {
if match.Type == "" || match.Type == "test" {
return ""
} else if match.Type == "elimination" {
return "Playoff"

View File

@@ -15,6 +15,7 @@ import (
"io/ioutil"
"net/http"
"strconv"
"strings"
)
const (
@@ -38,6 +39,7 @@ type TbaMatch struct {
Alliances map[string]*TbaAlliance `json:"alliances"`
TimeString string `json:"time_string"`
TimeUtc string `json:"time_utc"`
DisplayName string `json:"display_name"`
}
type TbaAlliance struct {
@@ -331,8 +333,14 @@ func (client *TbaClient) PublishMatches(database *model.Database) error {
alliances["blue"] = createTbaAlliance([3]int{match.Blue1, match.Blue2, match.Blue3},
[3]bool{match.Blue1IsSurrogate, match.Blue2IsSurrogate, match.Blue3IsSurrogate}, blueScore)
tbaMatches[i] = TbaMatch{"qm", 0, matchNumber, alliances, match.Time.Local().Format("3:04 PM"),
match.Time.UTC().Format("2006-01-02T15:04:05")}
tbaMatches[i] = TbaMatch{
CompLevel: "qm",
SetNumber: 0,
MatchNumber: matchNumber,
Alliances: alliances,
TimeString: match.Time.Local().Format("3:04 PM"),
TimeUtc: match.Time.UTC().Format("2006-01-02T15:04:05"),
}
if match.Type == "elimination" {
setElimMatchKey(&tbaMatches[i], &match, eventSettings.ElimType)
}
@@ -553,5 +561,8 @@ func setElimMatchKey(tbaMatch *TbaMatch, match *model.Match, elimType string) {
tbaMatch.SetNumber = tbaKey.setNumber
}
tbaMatch.MatchNumber = match.ElimInstance
if !strings.HasPrefix(match.DisplayName, "F") {
tbaMatch.DisplayName = "Match " + match.DisplayName
}
}
}

View File

@@ -38,6 +38,7 @@ const (
)
// Discrete inputs
//
//go:generate stringer -type=input
type input int
@@ -59,6 +60,7 @@ const (
)
// 16-bit registers
//
//go:generate stringer -type=register
type register int
@@ -68,6 +70,7 @@ const (
)
// Coils
//
//go:generate stringer -type=coil
type coil int
@@ -84,6 +87,7 @@ const (
)
// Bitmask for decoding fieldIoConnection into individual ArmorBlock connection statuses.
//
//go:generate stringer -type=armorBlock
type armorBlock int

View File

@@ -120,8 +120,8 @@ body[data-position=right] #inMatch #blueScore {
left: 0;
right: 0;
margin: 0 auto;
font-size: 550px;
line-height: 550px;
font-size: 450px;
line-height: 450px;
text-align: center;
}
#preMatch .databar {

View File

@@ -449,6 +449,9 @@ html {
opacity: 0;
text-align: center;
}
#bracketSvg {
width: 100%;
}
#sponsor {
position: fixed;
width: 1000px;

View File

@@ -38,3 +38,6 @@ body {
margin: auto auto;
text-align: center;
}
#bracketSvg {
width: 100%;
}

View File

@@ -105,7 +105,7 @@ td[data-plc-value="true"] {
color: #090;
}
.btn-game-sound {
width: 110px;
width: 160px;
text-align: left;
}
input[data-changed="true"], select[data-changed="true"] {

View File

@@ -34,7 +34,7 @@ h1 {
margin-bottom: 15px;
}
#matchState, #matchTime {
font-size: 35px;
font-size: 25px;
color: #666;
}
#matchTime {

View File

@@ -170,7 +170,7 @@ var handleScorePosted = function(data) {
$("#finalMatchName").text(data.MatchType + " " + data.Match.DisplayName);
// Reload the bracket to reflect any changes.
$("#bracketSvg").attr("src", "/api/bracket/svg?v=" + new Date().getTime());
$("#bracketSvg").attr("src", "/api/bracket/svg?activeMatch=saved&v=" + new Date().getTime());
};
// Handles a websocket message to play a sound to signal match start/stop/etc.

View File

@@ -5,14 +5,14 @@
var websocket;
// Handles a websocket message to populate the final score data, which also triggers a bracket update.
const handleScorePosted = function(data) {
$("#bracketSvg").attr("src", "/api/bracket/svg?v=" + new Date().getTime());
// Handles a websocket message to load a new match.
const handleMatchLoad = function(data) {
$("#bracketSvg").attr("src", "/api/bracket/svg?activeMatch=current&v=" + new Date().getTime());
};
$(function() {
// Set up the websocket back to the server.
websocket = new CheesyWebsocket("/displays/bracket/websocket", {
scorePosted: function(event) { handleScorePosted(event.data); },
matchLoad: function(event) { handleMatchLoad(event.data); },
});
});

View File

@@ -211,8 +211,8 @@
.bracket_double #match_3_2 {transform: translate(709px, 504px);}
.bracket_double #match_3_1 {transform: translate(709px, 694px);}
.bracket_double #match_4_2 {transform: translate(1006px, 301px);}
.bracket_double #match_4_1 {transform: translate(1006px, 599px);}
.bracket_double #match_4_1 {transform: translate(1006px, 301px);}
.bracket_double #match_4_2 {transform: translate(1006px, 599px);}
.bracket_double #match_5_1 {transform: translate(1302px, 567px);}
@@ -278,146 +278,148 @@
<polyline points="617,247 703,247 703,437 617,437"/>
<polyline points="1006,390 861,390 861,336 704,336"/>
</g>
<g id="connectors_temporary">
<g id="connector_1_1"{{if (index .Matchups "1_1").IsActive}} class="active"{{end}}>
<polyline class="loser" points="411,593 367,593 367,247"/>
<polyline points="319,247 367,247 367,214 411,214"/>
<text transform="translate(342.9489 228.3672)">W</text>
<text transform="translate(347.4327 269.9525)" class="loser">L</text>
{{if .ShowTemporaryConnectors}}
<g id="connectors_temporary">
<g id="connector_1_1"{{if (index .Matchups "1_1").IsActive}} class="active"{{end}}>
<polyline class="loser" points="411,593 367,593 367,247"/>
<polyline points="319,247 367,247 367,214 411,214"/>
<text transform="translate(342.9489 228.3672)">W</text>
<text transform="translate(347.4327 269.9525)" class="loser">L</text>
</g>
<g id="connectors_1_2"{{if (index .Matchups "1_2").IsActive}} class="active"{{end}}>
<polyline class="loser" points="411,662 367,662 367,437"/>
<polyline points="319,437 367,437 367,283 411,283"/>
<text transform="translate(342.9489 420.848)">W</text>
<text transform="translate(347.4327 462.4333)" class="loser">L</text>
</g>
<g id="connectors_1_3"{{if (index .Matchups "1_3").IsActive}} class="active"{{end}}>
<polyline class="loser" points="411,786 367,786 367,627"/>
<polyline points="319,627 367,627 367,404 411,404"/>
<text transform="translate(342.9489 610.848)">W</text>
<text transform="translate(347.4327 652.4332)" class="loser">L</text>
</g>
<g id="connectors_1_4"{{if (index .Matchups "1_4").IsActive}} class="active"{{end}}>
<polyline class="loser" points="411,853 367,853 367,817"/>
<polyline points="319,817 367,817 367,473 411,473"/>
<text transform="translate(342.9489 800.848)">W</text>
<text transform="translate(347.4327 842.4332)" class="loser">L</text>
</g>
<g id="connectors_2_1"{{if (index .Matchups "2_1").IsActive}} class="active"{{end}}>
<polyline class="loser" points="319,247 374,247 374,597 411,597"/>
<text transform="translate(665.9388 616.8822)">W</text>
<text transform="translate(645.3726 654.1893)" class="loser">L</text>
<polyline class="loser" points="319,437 360,437 360,662 411,662"/>
<line class="loser" x1="660" y1="628" x2="660" y2="675"/>
<line class="loser" x1="668.485" y1="666.515" x2="651.515" y2="683.485"/>
<line class="loser" x1="668.485" y1="683.485" x2="651.515" y2="666.515"/>
<text transform="translate(330.706 429.7347)" class="loser">L</text>
<text transform="translate(330.706 240.7347)" class="loser">L</text>
</g>
<g id="connectors_2_2"{{if (index .Matchups "2_2").IsActive}} class="active"{{end}}>
<polyline class="loser" points="319,627 374,627 374,787 411,787"/>
<text transform="translate(667.1932 808.262)">W</text>
<text transform="translate(645.3726 844.1893)" class="loser">L</text>
<polyline class="loser" points="319,817 360,817 360,852 411,852"/>
<line class="loser" x1="660" y1="818" x2="660" y2="865"/>
<line class="loser" x1="668.485" y1="856.515" x2="651.515" y2="873.485"/>
<line class="loser" x1="668.485" y1="873.485" x2="651.515" y2="856.515"/>
<text transform="translate(330.706 619.7347)" class="loser">L</text>
<text transform="translate(330.706 808.462)" class="loser">L</text>
</g>
<g id="connectors_2_3"{{if (index .Matchups "2_3").IsActive}} class="active"{{end}}>
<rect class="coverup" x="699.216" y="241.054" width="312.117" height="199.156"/>
<polyline points="319,247 367,247 367,214 411,214"/>
<text transform="translate(668.4441 239.1465)">W</text>
<text transform="translate(644.3726 276.7044)" class="loser">L</text>
<polyline points="319,437 367,437 367,281 411,281"/>
<text transform="translate(332.4185 239.67)">W</text>
<text transform="translate(332.4185 429.67)">W</text>
<polyline class="loser" points="660,636 660,748 728,748"/>
<line class="loser" x1="660" y1="447" x2="660" y2="618"/>
<line class="loser" x1="660" y1="248" x2="660" y2="427"/>
<polyline points="698,247 790,247 790,358 1010,358"/>
<polyline points="698,437 790,437 790,421 1010,421"/>
</g>
<g id="connectors_2_4"{{if (index .Matchups "2_4").IsActive}} class="active"{{end}}>
<polyline points="319,627 360,627 360,405 411,405"/>
<text transform="translate(668.566 429.1972)">W</text>
<text transform="translate(643.3726 469.2499)" class="loser">L</text>
<polyline points="319,817 374,817 374,473 411,473"/>
<polyline class="loser" points="660,438 660,561 728,561"/>
<text transform="translate(332.4185 618.67)">W</text>
<text transform="translate(332.4185 808.67)">W</text>
<rect class="coverup" x="699.216" y="241.054" width="312.117" height="199.156"/>
<polyline points="698,247 790,247 790,358 1010,358"/>
<polyline points="698,437 790,437 790,421 1010,421"/>
</g>
<g id="connectors_3_1"{{if (index .Matchups "3_1").IsActive}} class="active"{{end}}>
<polyline class="loser" points="660,637 660,748 709,748"/>
<text transform="translate(966.4487 773.8822)">W</text>
<text transform="translate(630.2617 808.2188)">W</text>
<text transform="translate(925.3726 811.1893)" class="loser">L</text>
<line class="loser" x1="940" y1="784" x2="940" y2="832"/>
<line class="loser" x1="948.485" y1="823.515" x2="931.515" y2="840.485"/>
<line class="loser" x1="948.485" y1="840.485" x2="931.515" y2="823.515"/>
<text transform="translate(640.4236 276.67)" class="loser">L</text>
<line class="loser" x1="660" y1="248" x2="660" y2="425"/>
<line class="loser" x1="660" y1="447" x2="660" y2="615"/>
</g>
<g id="connectors_3_2"{{if (index .Matchups "3_2").IsActive}} class="active"{{end}}>
<polyline class="loser" points="660,438 660,563 709,563"/>
<text transform="translate(941.2606 585.4622)">W</text>
<text transform="translate(630.8534 616.8523)">W</text>
<text transform="translate(925.3726 620.1893)" class="loser">L</text>
<line class="loser" x1="940" y1="594" x2="940" y2="641"/>
<line class="loser" x1="948.485" y1="632.515" x2="931.515" y2="649.485"/>
<line class="loser" x1="948.485" y1="649.485" x2="931.515" y2="632.515"/>
<text transform="translate(640.2857 472.1667)" class="loser">L</text>
</g>
<g id="connectors_4_1"{{if (index .Matchups "4_1").IsActive}} class="active"{{end}}>
<rect class="coverup" x="699.216" y="241.054" width="312.117" height="199.156"/>
<polyline points="698,247 790,247 790,358 1010,358"/>
<polyline points="698,437 790,437 790,421 1010,421"/>
<text transform="translate(628.5344 429.1004)">W</text>
<text transform="translate(628.5344 239.1004)">W</text>
<text transform="translate(1263.0288 382.2166)">W</text>
<text transform="translate(1239.3726 418.7044)" class="loser">L</text>
<polyline class="loser" points="1256,391 1256,625 1323,625"/>
</g>
<g id="connectors_4_2"{{if (index .Matchups "4_2").IsActive}} class="active"{{end}}>
<rect class="coverup" x="955.326" y="589.109" width="68.612" height="200.486"/>
<text transform="translate(1223.2803 681.0883)">W</text>
<text transform="translate(1223.3726 717.1893)" class="loser">L</text>
<line class="loser" x1="1238" y1="689" x2="1238" y2="738"/>
<line class="loser" x1="1246.485" y1="729.515" x2="1229.515" y2="746.485"/>
<line class="loser" x1="1246.485" y1="746.485" x2="1229.515" y2="729.515"/>
<text transform="translate(926.2617 775.3125)">W</text>
<text transform="translate(926.2617 585.3125)">W</text>
<polyline points="955,593 955,655 1008,655"/>
<polyline points="955,783 955,725 1008,725"/>
</g>
<g id="connectors_5_1"{{if (index .Matchups "5_1").IsActive}} class="active"{{end}}>
<rect class="coverup" x="1523.794" y="381.275" width="83.494" height="287.877"/>
<polyline points="1481,390 1553,390 1553,474 1633,474"/>
<polyline points="1481,656 1553,656 1553,542 1633,542"/>
<text transform="translate(628.5344 429.1004)">W</text>
<text transform="translate(628.5344 239.1004)">W</text>
<text transform="translate(1562.4487 647.8822)">W</text>
<line class="loser" x1="1538" y1="657" x2="1538" y2="706"/>
<line class="loser" x1="1546.485" y1="697.515" x2="1529.515" y2="714.485"/>
<line class="loser" x1="1546.485" y1="714.485" x2="1529.515" y2="697.515"/>
<text transform="translate(1223.4487 680.8822)">W</text>
<text transform="translate(1239.3726 418.7044)" class="loser">L</text>
<polyline class="loser" points="1256,391 1256,625 1323,625"/>
<text transform="translate(1522.3726 684.1893)" class="loser">L</text>
</g>
<g id="connectors_6_1"{{if (index .Matchups "6_1").IsActive}} class="active"{{end}}>
<rect class="coverup" x="1523.794" y="381.275" width="83.494" height="287.877"/>
<polyline points="1481,390 1553,390 1553,474 1633,474"/>
<polyline points="1481,656 1553,656 1553,542 1633,542"/>
<text transform="translate(1518.4487 647.8822)">W</text>
<text transform="translate(1225.4487 382.1549)">W</text>
</g>
</g>
<g id="connectors_1_2"{{if (index .Matchups "1_2").IsActive}} class="active"{{end}}>
<polyline class="loser" points="411,662 367,662 367,437"/>
<polyline points="319,437 367,437 367,283 411,283"/>
<text transform="translate(342.9489 420.848)">W</text>
<text transform="translate(347.4327 462.4333)" class="loser">L</text>
</g>
<g id="connectors_1_3"{{if (index .Matchups "1_3").IsActive}} class="active"{{end}}>
<polyline class="loser" points="411,786 367,786 367,627"/>
<polyline points="319,627 367,627 367,404 411,404"/>
<text transform="translate(342.9489 610.848)">W</text>
<text transform="translate(347.4327 652.4332)" class="loser">L</text>
</g>
<g id="connectors_1_4"{{if (index .Matchups "1_4").IsActive}} class="active"{{end}}>
<polyline class="loser" points="411,853 367,853 367,817"/>
<polyline points="319,817 367,817 367,473 411,473"/>
<text transform="translate(342.9489 800.848)">W</text>
<text transform="translate(347.4327 842.4332)" class="loser">L</text>
</g>
<g id="connectors_2_1"{{if (index .Matchups "2_1").IsActive}} class="active"{{end}}>
<polyline class="loser" points="319,247 374,247 374,597 411,597"/>
<text transform="translate(665.9388 616.8822)">W</text>
<text transform="translate(645.3726 654.1893)" class="loser">L</text>
<polyline class="loser" points="319,437 360,437 360,662 411,662"/>
<line class="loser" x1="660" y1="628" x2="660" y2="675"/>
<line class="loser" x1="668.485" y1="666.515" x2="651.515" y2="683.485"/>
<line class="loser" x1="668.485" y1="683.485" x2="651.515" y2="666.515"/>
<text transform="translate(330.706 429.7347)" class="loser">L</text>
<text transform="translate(330.706 240.7347)" class="loser">L</text>
</g>
<g id="connectors_2_2"{{if (index .Matchups "2_2").IsActive}} class="active"{{end}}>
<polyline class="loser" points="319,627 374,627 374,787 411,787"/>
<text transform="translate(667.1932 808.262)">W</text>
<text transform="translate(645.3726 844.1893)" class="loser">L</text>
<polyline class="loser" points="319,817 360,817 360,852 411,852"/>
<line class="loser" x1="660" y1="818" x2="660" y2="865"/>
<line class="loser" x1="668.485" y1="856.515" x2="651.515" y2="873.485"/>
<line class="loser" x1="668.485" y1="873.485" x2="651.515" y2="856.515"/>
<text transform="translate(330.706 619.7347)" class="loser">L</text>
<text transform="translate(330.706 808.462)" class="loser">L</text>
</g>
<g id="connectors_2_3"{{if (index .Matchups "2_3").IsActive}} class="active"{{end}}>
<rect class="coverup" x="699.216" y="241.054" width="312.117" height="199.156"/>
<polyline points="319,247 367,247 367,214 411,214"/>
<text transform="translate(668.4441 239.1465)">W</text>
<text transform="translate(644.3726 276.7044)" class="loser">L</text>
<polyline points="319,437 367,437 367,281 411,281"/>
<text transform="translate(332.4185 239.67)">W</text>
<text transform="translate(332.4185 429.67)">W</text>
<polyline class="loser" points="660,636 660,748 728,748"/>
<line class="loser" x1="660" y1="447" x2="660" y2="618"/>
<line class="loser" x1="660" y1="248" x2="660" y2="427"/>
<polyline points="698,247 790,247 790,358 1010,358"/>
<polyline points="698,437 790,437 790,421 1010,421"/>
</g>
<g id="connectors_2_4"{{if (index .Matchups "2_4").IsActive}} class="active"{{end}}>
<polyline points="319,627 360,627 360,405 411,405"/>
<text transform="translate(668.566 429.1972)">W</text>
<text transform="translate(643.3726 469.2499)" class="loser">L</text>
<polyline points="319,817 374,817 374,473 411,473"/>
<polyline class="loser" points="660,438 660,561 728,561"/>
<text transform="translate(332.4185 618.67)">W</text>
<text transform="translate(332.4185 808.67)">W</text>
<rect class="coverup" x="699.216" y="241.054" width="312.117" height="199.156"/>
<polyline points="698,247 790,247 790,358 1010,358"/>
<polyline points="698,437 790,437 790,421 1010,421"/>
</g>
<g id="connectors_3_1"{{if (index .Matchups "3_1").IsActive}} class="active"{{end}}>
<polyline class="loser" points="660,637 660,748 709,748"/>
<text transform="translate(966.4487 773.8822)">W</text>
<text transform="translate(630.2617 808.2188)">W</text>
<text transform="translate(925.3726 811.1893)" class="loser">L</text>
<line class="loser" x1="940" y1="784" x2="940" y2="832"/>
<line class="loser" x1="948.485" y1="823.515" x2="931.515" y2="840.485"/>
<line class="loser" x1="948.485" y1="840.485" x2="931.515" y2="823.515"/>
<text transform="translate(640.4236 276.67)" class="loser">L</text>
<line class="loser" x1="660" y1="248" x2="660" y2="425"/>
<line class="loser" x1="660" y1="447" x2="660" y2="615"/>
</g>
<g id="connectors_3_2"{{if (index .Matchups "3_2").IsActive}} class="active"{{end}}>
<polyline class="loser" points="660,438 660,563 709,563"/>
<text transform="translate(941.2606 585.4622)">W</text>
<text transform="translate(630.8534 616.8523)">W</text>
<text transform="translate(925.3726 620.1893)" class="loser">L</text>
<line class="loser" x1="940" y1="594" x2="940" y2="641"/>
<line class="loser" x1="948.485" y1="632.515" x2="931.515" y2="649.485"/>
<line class="loser" x1="948.485" y1="649.485" x2="931.515" y2="632.515"/>
<text transform="translate(640.2857 472.1667)" class="loser">L</text>
</g>
<g id="connectors_4_1"{{if (index .Matchups "4_1").IsActive}} class="active"{{end}}>
<rect class="coverup" x="955.326" y="589.109" width="68.612" height="200.486"/>
<text transform="translate(1223.2803 681.0883)">W</text>
<text transform="translate(1223.3726 717.1893)" class="loser">L</text>
<line class="loser" x1="1238" y1="689" x2="1238" y2="738"/>
<line class="loser" x1="1246.485" y1="729.515" x2="1229.515" y2="746.485"/>
<line class="loser" x1="1246.485" y1="746.485" x2="1229.515" y2="729.515"/>
<text transform="translate(926.2617 775.3125)">W</text>
<text transform="translate(926.2617 585.3125)">W</text>
<polyline points="955,593 955,655 1008,655"/>
<polyline points="955,783 955,725 1008,725"/>
</g>
<g id="connectors_4_2"{{if (index .Matchups "4_2").IsActive}} class="active"{{end}}>
<rect class="coverup" x="699.216" y="241.054" width="312.117" height="199.156"/>
<polyline points="698,247 790,247 790,358 1010,358"/>
<polyline points="698,437 790,437 790,421 1010,421"/>
<text transform="translate(628.5344 429.1004)">W</text>
<text transform="translate(628.5344 239.1004)">W</text>
<text transform="translate(1263.0288 382.2166)">W</text>
<text transform="translate(1239.3726 418.7044)" class="loser">L</text>
<polyline class="loser" points="1256,391 1256,625 1323,625"/>
</g>
<g id="connectors_5_1"{{if (index .Matchups "5_1").IsActive}} class="active"{{end}}>
<rect class="coverup" x="1523.794" y="381.275" width="83.494" height="287.877"/>
<polyline points="1481,390 1553,390 1553,474 1633,474"/>
<polyline points="1481,656 1553,656 1553,542 1633,542"/>
<text transform="translate(628.5344 429.1004)">W</text>
<text transform="translate(628.5344 239.1004)">W</text>
<text transform="translate(1562.4487 647.8822)">W</text>
<line class="loser" x1="1538" y1="657" x2="1538" y2="706"/>
<line class="loser" x1="1546.485" y1="697.515" x2="1529.515" y2="714.485"/>
<line class="loser" x1="1546.485" y1="714.485" x2="1529.515" y2="697.515"/>
<text transform="translate(1223.4487 680.8822)">W</text>
<text transform="translate(1239.3726 418.7044)" class="loser">L</text>
<polyline class="loser" points="1256,391 1256,625 1323,625"/>
<text transform="translate(1522.3726 684.1893)" class="loser">L</text>
</g>
<g id="connectors_6_1"{{if (index .Matchups "6_1").IsActive}} class="active"{{end}}>
<rect class="coverup" x="1523.794" y="381.275" width="83.494" height="287.877"/>
<polyline points="1481,390 1553,390 1553,474 1633,474"/>
<polyline points="1481,656 1553,656 1553,542 1633,542"/>
<text transform="translate(1518.4487 647.8822)">W</text>
<text transform="translate(1225.4487 382.1549)">W</text>
</g>
</g>
{{end}}
</g>
{{else}}
<g id="connectors_standardbracket">

View File

@@ -7,10 +7,12 @@ import (
"github.com/Team254/cheesy-arena-lite/game"
"github.com/Team254/cheesy-arena-lite/model"
"github.com/stretchr/testify/assert"
"math/rand"
"testing"
)
func TestCalculateRankings(t *testing.T) {
rand.Seed(1)
database := setupTestDb(t)
setupMatchResultsForRankings(database)

View File

@@ -228,27 +228,29 @@ func (web *Web) teamAvatarsApiHandler(w http.ResponseWriter, r *http.Request) {
}
func (web *Web) bracketSvgApiHandler(w http.ResponseWriter, r *http.Request) {
hideActive := false
if hideActiveValue, ok := r.URL.Query()["hideActive"]; ok {
hideActive = hideActiveValue[0] == "true"
var activeMatch *model.Match
showTemporaryConnectors := false
if activeMatchValue, ok := r.URL.Query()["activeMatch"]; ok {
if activeMatchValue[0] == "current" {
activeMatch = web.arena.CurrentMatch
} else if activeMatchValue[0] == "saved" {
activeMatch = web.arena.SavedMatch
showTemporaryConnectors = true
}
}
w.Header().Set("Content-Type", "image/svg+xml")
if err := web.generateBracketSvg(w, hideActive); err != nil {
if err := web.generateBracketSvg(w, activeMatch, showTemporaryConnectors); err != nil {
handleWebErr(w, err)
return
}
}
func (web *Web) generateBracketSvg(w io.Writer, hideActive bool) error {
func (web *Web) generateBracketSvg(w io.Writer, activeMatch *model.Match, showTemporaryConnectors bool) error {
alliances, err := web.arena.Database.GetAllAlliances()
if err != nil {
return err
}
var activeMatch *model.Match
if !hideActive {
activeMatch = web.arena.SavedMatch
}
matchups := make(map[string]*allianceMatchup)
if web.arena.PlayoffBracket != nil {
@@ -303,8 +305,9 @@ func (web *Web) generateBracketSvg(w io.Writer, hideActive bool) error {
return err
}
data := struct {
BracketType string
Matchups map[string]*allianceMatchup
}{bracketType, matchups}
BracketType string
Matchups map[string]*allianceMatchup
ShowTemporaryConnectors bool
}{bracketType, matchups, showTemporaryConnectors}
return template.ExecuteTemplate(w, "bracket", data)
}

View File

@@ -49,5 +49,5 @@ func (web *Web) bracketDisplayWebsocketHandler(w http.ResponseWriter, r *http.Re
defer ws.Close()
// Subscribe the websocket to the notifiers whose messages will be passed on to the client.
ws.HandleNotifiers(display.Notifier, web.arena.ScorePostedNotifier, web.arena.ReloadDisplaysNotifier)
ws.HandleNotifiers(display.Notifier, web.arena.MatchLoadNotifier, web.arena.ReloadDisplaysNotifier)
}

View File

@@ -30,5 +30,5 @@ func TestBracketDisplayWebsocket(t *testing.T) {
// Should get a few status updates right after connection.
readWebsocketType(t, ws, "displayConfiguration")
readWebsocketType(t, ws, "scorePosted")
readWebsocketType(t, ws, "matchLoad")
}

View File

@@ -681,7 +681,7 @@ func (web *Web) alliancesPdfReportHandler(w http.ResponseWriter, r *http.Request
// suitable Go library for doing so appears to exist).
func (web *Web) bracketPdfReportHandler(w http.ResponseWriter, r *http.Request) {
buffer := new(bytes.Buffer)
err := web.generateBracketSvg(buffer, true)
err := web.generateBracketSvg(buffer, nil, false)
if err != nil {
handleWebErr(w, err)
return