mirror of
https://github.com/Team254/cheesy-arena-lite.git
synced 2026-03-09 21:56:50 -04:00
Added match play screen with fake match scoring.
This commit is contained in:
189
match_play.go
Normal file
189
match_play.go
Normal file
@@ -0,0 +1,189 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
//
|
||||
// Web routes for controlling match play.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gorilla/mux"
|
||||
"html/template"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"sort"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type MatchPlayListItem struct {
|
||||
Id int
|
||||
DisplayName string
|
||||
Time string
|
||||
ColorClass string
|
||||
}
|
||||
|
||||
type MatchPlayList []MatchPlayListItem
|
||||
|
||||
// Global var to hold the current active tournament so that its matches are displayed by default.
|
||||
var currentMatchType string
|
||||
|
||||
// Shows the match play control interface.
|
||||
func MatchPlayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
practiceMatches, err := buildMatchPlayList("practice")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
qualificationMatches, err := buildMatchPlayList("qualification")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
eliminationMatches, err := buildMatchPlayList("elimination")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
template, err := template.ParseFiles("templates/match_play.html", "templates/base.html")
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
matchesByType := map[string]MatchPlayList{"practice": practiceMatches,
|
||||
"qualification": qualificationMatches, "elimination": eliminationMatches}
|
||||
if currentMatchType == "" {
|
||||
currentMatchType = "practice"
|
||||
}
|
||||
data := struct {
|
||||
*EventSettings
|
||||
MatchesByType map[string]MatchPlayList
|
||||
CurrentMatchType string
|
||||
}{eventSettings, matchesByType, currentMatchType}
|
||||
err = template.ExecuteTemplate(w, "base", data)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func MatchPlayFakeResultHandler(w http.ResponseWriter, r *http.Request) {
|
||||
vars := mux.Vars(r)
|
||||
matchId, _ := strconv.Atoi(vars["matchId"])
|
||||
match, err := db.GetMatchById(matchId)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
if match == nil {
|
||||
handleWebErr(w, fmt.Errorf("Invalid match ID %d.", matchId))
|
||||
return
|
||||
}
|
||||
matchResult := MatchResult{MatchId: match.Id}
|
||||
matchResult.RedScore = randomScore()
|
||||
matchResult.BlueScore = randomScore()
|
||||
err = CommitMatchScore(match, &matchResult)
|
||||
if err != nil {
|
||||
handleWebErr(w, err)
|
||||
return
|
||||
}
|
||||
currentMatchType = match.Type
|
||||
|
||||
http.Redirect(w, r, "/match_play", 302)
|
||||
}
|
||||
|
||||
func CommitMatchScore(match *Match, matchResult *MatchResult) error {
|
||||
// Determine the play number for this match.
|
||||
prevMatchResult, err := db.GetMatchResultForMatch(match.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if prevMatchResult != nil {
|
||||
matchResult.PlayNumber = prevMatchResult.PlayNumber + 1
|
||||
} else {
|
||||
matchResult.PlayNumber = 1
|
||||
}
|
||||
|
||||
// Save the match result record to the database.
|
||||
err = db.CreateMatchResult(matchResult)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Update and save the match record to the database.
|
||||
match.Status = "complete"
|
||||
redScore := matchResult.RedScoreSummary()
|
||||
blueScore := matchResult.BlueScoreSummary()
|
||||
if redScore.Score > blueScore.Score {
|
||||
match.Winner = "R"
|
||||
} else if redScore.Score < blueScore.Score {
|
||||
match.Winner = "B"
|
||||
} else {
|
||||
match.Winner = "T"
|
||||
}
|
||||
err = db.SaveMatch(match)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Recalculate all the rankings.
|
||||
err = db.CalculateRankings()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (list MatchPlayList) Len() int {
|
||||
return len(list)
|
||||
}
|
||||
|
||||
func (list MatchPlayList) Less(i, j int) bool {
|
||||
return list[i].ColorClass == "" && list[j].ColorClass != ""
|
||||
}
|
||||
|
||||
func (list MatchPlayList) Swap(i, j int) {
|
||||
list[i], list[j] = list[j], list[i]
|
||||
}
|
||||
|
||||
func buildMatchPlayList(matchType string) (MatchPlayList, error) {
|
||||
matches, err := db.GetMatchesByType(matchType)
|
||||
if err != nil {
|
||||
return MatchPlayList{}, err
|
||||
}
|
||||
|
||||
prefix := ""
|
||||
if matchType == "practice" {
|
||||
prefix = "P"
|
||||
} else if matchType == "qualification" {
|
||||
prefix = "Q"
|
||||
}
|
||||
matchPlayList := make(MatchPlayList, len(matches))
|
||||
for i, match := range matches {
|
||||
matchPlayList[i].Id = match.Id
|
||||
matchPlayList[i].DisplayName = prefix + match.DisplayName
|
||||
matchPlayList[i].Time = match.Time.Format("3:04 PM")
|
||||
switch match.Winner {
|
||||
case "R":
|
||||
matchPlayList[i].ColorClass = "danger"
|
||||
case "B":
|
||||
matchPlayList[i].ColorClass = "info"
|
||||
case "T":
|
||||
matchPlayList[i].ColorClass = "warning"
|
||||
default:
|
||||
matchPlayList[i].ColorClass = ""
|
||||
}
|
||||
}
|
||||
|
||||
// Sort the list to put all completed matches at the bottom.
|
||||
sort.Stable(matchPlayList)
|
||||
|
||||
return matchPlayList, nil
|
||||
}
|
||||
|
||||
func randomScore() Score {
|
||||
cycle := Cycle{rand.Intn(3) + 1, rand.Intn(2) == 1, rand.Intn(2) == 1, rand.Intn(2) == 1, rand.Intn(2) == 1,
|
||||
rand.Intn(2) == 1}
|
||||
return Score{rand.Intn(4), rand.Intn(4), rand.Intn(4), rand.Intn(4), rand.Intn(4), 0, 0, []Cycle{cycle}}
|
||||
}
|
||||
39
match_play_test.go
Normal file
39
match_play_test.go
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright 2014 Team 254. All Rights Reserved.
|
||||
// Author: pat@patfairbank.com (Patrick Fairbank)
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMatchPlay(t *testing.T) {
|
||||
clearDb()
|
||||
defer clearDb()
|
||||
var err error
|
||||
db, err = OpenDatabase(testDbPath)
|
||||
assert.Nil(t, err)
|
||||
defer db.Close()
|
||||
eventSettings, _ = db.GetEventSettings()
|
||||
|
||||
match1 := Match{Type: "practice", DisplayName: "1", Status: "complete", Winner: "R"}
|
||||
match2 := Match{Type: "practice", DisplayName: "2"}
|
||||
match3 := Match{Type: "qualification", DisplayName: "1", Status: "complete", Winner: "B"}
|
||||
match4 := Match{Type: "elimination", DisplayName: "SF1-1", Status: "complete", Winner: "T"}
|
||||
match5 := Match{Type: "elimination", DisplayName: "SF1-2"}
|
||||
db.CreateMatch(&match1)
|
||||
db.CreateMatch(&match2)
|
||||
db.CreateMatch(&match3)
|
||||
db.CreateMatch(&match4)
|
||||
db.CreateMatch(&match5)
|
||||
|
||||
// Check that all matches are listed on the page.
|
||||
recorder := getHttpResponse("/match_play")
|
||||
assert.Equal(t, 200, recorder.Code)
|
||||
assert.Contains(t, recorder.Body.String(), "P1")
|
||||
assert.Contains(t, recorder.Body.String(), "P2")
|
||||
assert.Contains(t, recorder.Body.String(), "Q1")
|
||||
assert.Contains(t, recorder.Body.String(), "SF1-1")
|
||||
assert.Contains(t, recorder.Body.String(), "SF1-2")
|
||||
}
|
||||
@@ -36,7 +36,7 @@
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Run</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#">Match Play</a></li>
|
||||
<li><a href="/match_play">Match Play</a></li>
|
||||
<li><a href="#">Match Review</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
54
templates/match_play.html
Normal file
54
templates/match_play.html
Normal file
@@ -0,0 +1,54 @@
|
||||
{{define "title"}}Match Play{{end}}
|
||||
{{define "body"}}
|
||||
<div class="row">
|
||||
<div class="col-lg-4">
|
||||
<ul class="nav nav-tabs" style="margin-bottom: 15px;">
|
||||
<li{{if eq .CurrentMatchType "practice" }} class="active"{{end}}>
|
||||
<a href="#practice" data-toggle="tab">Practice</a>
|
||||
</li>
|
||||
<li{{if eq .CurrentMatchType "qualification" }} class="active"{{end}}>
|
||||
<a href="#qualification" data-toggle="tab">Qualification</a>
|
||||
</li>
|
||||
<li{{if eq .CurrentMatchType "elimination" }} class="active"{{end}}>
|
||||
<a href="#elimination" data-toggle="tab">Elimination</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="tab-content">
|
||||
{{range $type, $matches := .MatchesByType}}
|
||||
<div class="tab-pane {{if eq $.CurrentMatchType $type }} active{{end}}" id="{{$type}}">
|
||||
<table class="table table-striped table-hover ">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Match</th>
|
||||
<th>Time</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range $match := $matches}}
|
||||
<tr class="{{$match.ColorClass}}">
|
||||
<td>{{$match.DisplayName}}</td>
|
||||
<td>{{$match.Time}}</td>
|
||||
<td class="text-center" style="white-space: nowrap;">
|
||||
<a href="/match_play/{{$match.Id}}/generate_fake_result">
|
||||
<b class="btn btn-info btn-xs">Generate Fake Result</b>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-lg-8">
|
||||
<div class="jumbotron">
|
||||
<h2>Placeholder for the match play interface.</h2>
|
||||
<p>For now, use the "Generate Fake Result" buttons to simulate matches being played and scored.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
{{define "script"}}
|
||||
{{end}}
|
||||
2
web.go
2
web.go
@@ -82,6 +82,8 @@ func newHandler() http.Handler {
|
||||
router.HandleFunc("/setup/alliance_selection/start", AllianceSelectionStartHandler).Methods("POST")
|
||||
router.HandleFunc("/setup/alliance_selection/reset", AllianceSelectionResetHandler).Methods("POST")
|
||||
router.HandleFunc("/setup/alliance_selection/finalize", AllianceSelectionFinalizeHandler).Methods("POST")
|
||||
router.HandleFunc("/match_play", MatchPlayHandler).Methods("GET")
|
||||
router.HandleFunc("/match_play/{matchId}/generate_fake_result", MatchPlayFakeResultHandler).Methods("GET")
|
||||
router.HandleFunc("/reports/csv/rankings", RankingsCsvReportHandler)
|
||||
router.HandleFunc("/reports/pdf/rankings", RankingsPdfReportHandler)
|
||||
router.HandleFunc("/reports/json/rankings", RankingsJSONReportHandler)
|
||||
|
||||
Reference in New Issue
Block a user