ictgj-voting/admin_votes.go

172 lines
3.9 KiB
Go
Raw Normal View History

package main
import (
"errors"
"net/http"
2017-07-06 17:09:49 +00:00
"time"
"github.com/gorilla/mux"
)
2017-07-28 19:36:14 +00:00
type Ranking struct {
Rank int
Teams []Team
}
// getCondorcetResult returns the ranking of teams based on the condorcet method
// https://en.wikipedia.org/wiki/Condorcet_method
2017-07-28 19:36:14 +00:00
func getCondorcetResult() []Ranking {
type teamPair struct {
winner *Team
loser *Team
majority float32
2017-07-06 17:09:49 +00:00
}
var allPairs []teamPair
2017-07-28 19:36:14 +00:00
var ret []Ranking
2017-10-19 19:53:07 +00:00
for i := 0; i < len(m.jam.Teams); i++ {
for j := i + 1; j < len(m.jam.Teams); j++ {
// For each pairing find a winner
2017-10-19 19:53:07 +00:00
winner, pct, _ := findWinnerBetweenTeams(&m.jam.Teams[i], &m.jam.Teams[j])
2017-07-28 19:36:14 +00:00
newPair := new(teamPair)
if winner != nil {
newPair.winner = winner
2017-10-19 19:53:07 +00:00
if winner.UUID == m.jam.Teams[i].UUID {
newPair.loser = &m.jam.Teams[j]
} else {
2017-10-19 19:53:07 +00:00
newPair.loser = &m.jam.Teams[i]
}
newPair.majority = pct
2017-07-28 19:36:14 +00:00
} else {
2017-10-19 19:53:07 +00:00
newPair.winner = &m.jam.Teams[i]
newPair.loser = &m.jam.Teams[j]
2017-07-28 19:36:14 +00:00
newPair.majority = 50
2017-07-06 17:09:49 +00:00
}
2017-07-28 19:36:14 +00:00
allPairs = append(allPairs, *newPair)
2017-07-06 17:09:49 +00:00
}
}
2017-07-28 19:36:14 +00:00
// initialize map of team wins
teamWins := make(map[string]int)
2017-10-19 19:53:07 +00:00
for i := range m.jam.Teams {
teamWins[m.jam.Teams[i].UUID] = 0
}
2017-07-28 19:36:14 +00:00
// Figure out how many wins each team has
for i := range allPairs {
2017-07-28 19:36:14 +00:00
if allPairs[i].majority != 50 {
teamWins[allPairs[i].winner.UUID]++
}
}
2017-07-28 19:36:14 +00:00
// Rank them by wins
rankedWins := make(map[int][]string)
for k, v := range teamWins {
rankedWins[v] = append(rankedWins[v], k)
}
currRank := 1
for len(rankedWins) > 0 {
topWins := 0
2017-07-28 19:36:14 +00:00
for k, _ := range rankedWins {
if k > topWins {
topWins = k
2017-07-06 17:09:49 +00:00
}
}
2017-07-28 19:36:14 +00:00
nR := new(Ranking)
nR.Rank = currRank
for i := range rankedWins[topWins] {
2017-10-19 19:53:07 +00:00
tm, _ := m.jam.GetTeamById(rankedWins[topWins][i])
if tm != nil {
nR.Teams = append(nR.Teams, *tm)
}
}
2017-07-28 19:36:14 +00:00
ret = append(ret, *nR)
delete(rankedWins, topWins)
currRank++
2017-07-06 17:09:49 +00:00
}
return ret
}
// This is a helper function for calculating results
2017-07-28 19:36:14 +00:00
func uuidIsInRankingSlice(uuid string, sl []Ranking) bool {
for _, v := range sl {
2017-07-28 19:36:14 +00:00
for i := range v.Teams {
if v.Teams[i].UUID == uuid {
return true
}
2017-07-06 17:09:49 +00:00
}
}
return false
}
// findWinnerBetweenTeams returns the team that got the most votes
// and the percentage of votes they received
// or an error if a winner couldn't be determined.
func findWinnerBetweenTeams(tm1, tm2 *Team) (*Team, float32, error) {
// tally gets incremented for a tm1 win, decremented for a tm2 win
var tm1votes, tm2votes float32
2017-10-19 19:53:07 +00:00
for _, v := range m.jam.Votes {
for _, chc := range v.Choices {
if chc.Team == tm1.UUID {
tm1votes++
break
} else if chc.Team == tm2.UUID {
tm2votes++
break
}
2017-07-06 17:09:49 +00:00
}
}
ttlVotes := tm1votes + tm2votes
if tm1votes > tm2votes {
return tm1, 100 * (tm1votes / ttlVotes), nil
} else if tm1votes < tm2votes {
return tm2, 100 * (tm2votes / ttlVotes), nil
}
return nil, 50, errors.New("Unable to determine a winner")
2017-07-06 17:09:49 +00:00
}
func getInstantRunoffResult() []Team {
var ret []Team
return ret
}
func handleAdminVotes(w http.ResponseWriter, req *http.Request, page *pageData) {
vars := mux.Vars(req)
page.SubTitle = "Votes"
2017-07-06 17:09:49 +00:00
type vpdVote struct {
Timestamp string
ClientId string
Choices []Team
}
type votePageData struct {
AllVotes []vpdVote
2017-07-28 19:36:14 +00:00
Results []Ranking
2017-07-06 17:09:49 +00:00
}
vpd := new(votePageData)
2018-06-18 13:49:15 +00:00
now := time.Now()
dayThresh := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location())
2017-10-19 19:53:07 +00:00
for i := range m.jam.Votes {
2017-07-06 17:09:49 +00:00
v := new(vpdVote)
2018-06-18 13:49:15 +00:00
if m.jam.Votes[i].Timestamp.Before(dayThresh) {
v.Timestamp = m.jam.Votes[i].Timestamp.Format("Jan _2 15:04")
} else {
v.Timestamp = m.jam.Votes[i].Timestamp.Format(time.Kitchen)
}
2017-10-19 19:53:07 +00:00
v.ClientId = m.jam.Votes[i].ClientId
for _, choice := range m.jam.Votes[i].Choices {
for _, fndTm := range m.jam.Teams {
2017-07-06 17:09:49 +00:00
if fndTm.UUID == choice.Team {
v.Choices = append(v.Choices, fndTm)
break
}
}
}
vpd.AllVotes = append(vpd.AllVotes, *v)
}
vpd.Results = getCondorcetResult()
2017-07-06 17:09:49 +00:00
page.TemplateData = vpd
switch vars["function"] {
default:
page.show("admin-votes.html", w)
}
}