mirror of
https://github.com/jcreek/CosmicClash.git
synced 2026-09-15 16:42:06 +00:00
feat: add ranked season rollover policy
This commit is contained in:
+35
-11
@@ -28,10 +28,14 @@ func PartitionTeams(players []Candidate) (Teams, error) {
|
||||
var visit func(int)
|
||||
visit = func(start int) {
|
||||
if len(chosen) == teamSize {
|
||||
if !containsPlayer(chosen, anchor) { return }
|
||||
if !containsPlayer(chosen, anchor) {
|
||||
return
|
||||
}
|
||||
team1 := make([]Candidate, 0, teamSize)
|
||||
for _, player := range ordered {
|
||||
if !containsPlayer(chosen, player.PlayerID) { team1 = append(team1, player) }
|
||||
if !containsPlayer(chosen, player.PlayerID) {
|
||||
team1 = append(team1, player)
|
||||
}
|
||||
}
|
||||
if !found || betterTeams(chosen, team1, best) {
|
||||
best = Teams{Team0: append([]Candidate(nil), chosen...), Team1: team1}
|
||||
@@ -46,16 +50,24 @@ func PartitionTeams(players []Candidate) (Teams, error) {
|
||||
}
|
||||
}
|
||||
visit(0)
|
||||
if !found { return Teams{}, fmt.Errorf("no balanced team partition") }
|
||||
if !found {
|
||||
return Teams{}, fmt.Errorf("no balanced team partition")
|
||||
}
|
||||
return best, nil
|
||||
}
|
||||
|
||||
func betterTeams(team0, team1 []Candidate, best Teams) bool {
|
||||
if best.Team0 == nil { return true }
|
||||
if best.Team0 == nil {
|
||||
return true
|
||||
}
|
||||
meanDelta, maxOpposing := teamScore(team0, team1)
|
||||
bestMean, bestMaxOpposing := teamScore(best.Team0, best.Team1)
|
||||
if meanDelta != bestMean { return meanDelta < bestMean }
|
||||
if maxOpposing != bestMaxOpposing { return maxOpposing < bestMaxOpposing }
|
||||
if meanDelta != bestMean {
|
||||
return meanDelta < bestMean
|
||||
}
|
||||
if maxOpposing != bestMaxOpposing {
|
||||
return maxOpposing < bestMaxOpposing
|
||||
}
|
||||
return playerIDs(team0) < playerIDs(best.Team0)
|
||||
}
|
||||
|
||||
@@ -65,7 +77,9 @@ func teamScore(team0, team1 []Candidate) (float64, float64) {
|
||||
for _, left := range team0 {
|
||||
for _, right := range team1 {
|
||||
delta := abs(left.Rating - right.Rating)
|
||||
if delta > maxOpposing { maxOpposing = delta }
|
||||
if delta > maxOpposing {
|
||||
maxOpposing = delta
|
||||
}
|
||||
}
|
||||
}
|
||||
return abs(mean0 - mean1), maxOpposing
|
||||
@@ -73,20 +87,30 @@ func teamScore(team0, team1 []Candidate) (float64, float64) {
|
||||
|
||||
func meanRating(players []Candidate) float64 {
|
||||
total := 0.0
|
||||
for _, player := range players { total += player.Rating }
|
||||
for _, player := range players {
|
||||
total += player.Rating
|
||||
}
|
||||
return total / float64(len(players))
|
||||
}
|
||||
|
||||
func containsPlayer(players []Candidate, playerID string) bool {
|
||||
for _, player := range players { if player.PlayerID == playerID { return true } }
|
||||
for _, player := range players {
|
||||
if player.PlayerID == playerID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func playerIDs(players []Candidate) string {
|
||||
ids := make([]string, 0, len(players))
|
||||
for _, player := range players { ids = append(ids, player.PlayerID) }
|
||||
for _, player := range players {
|
||||
ids = append(ids, player.PlayerID)
|
||||
}
|
||||
sort.Strings(ids)
|
||||
result := ""
|
||||
for _, id := range ids { result += id + "\x00" }
|
||||
for _, id := range ids {
|
||||
result += id + "\x00"
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user