Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions controller/AdminController.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,13 @@ func SyncAIBoards(w http.ResponseWriter, r *http.Request) {
fmt.Println(w, "Team Ranks successfully generated.")
}

func AllocateAIRedshirts(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
seasonID := vars["seasonID"]
managers.AllocateAIRedshirts(seasonID)
http.ResponseWriter(w).Write([]byte("Redshirts allocated to AI teams."))
}

func RunTheGames(w http.ResponseWriter, r *http.Request) {
managers.RunTheGames()
fmt.Println(w, "Games for current week are set to run.")
Expand Down
2 changes: 2 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ func handleRequests() http.Handler {
apiRouter.HandleFunc("/admin/recruiting/class/size", controller.GetRecruitingClassSizeForTeams).Methods("GET")
apiRouter.HandleFunc("/admin/ai/fill/boards", controller.FillAIBoards).Methods("GET")
apiRouter.HandleFunc("/admin/ai/sync/boards", controller.SyncAIBoards).Methods("GET")
// This endpoint should be used right before the redshirt deadline.
apiRouter.HandleFunc("/admin/ai/apply/redshirts/{seasonID}", controller.AllocateAIRedshirts).Methods("GET")
// apiRouter.HandleFunc("/admin/fix/affinities", controller.RecalibrateCrootProfiles).Methods("GET")
apiRouter.HandleFunc("/admin/fix/recruit/points", controller.RecalibrateRecruitPoints).Methods("GET")
apiRouter.HandleFunc("/admin/run/the/games/", controller.RunTheGames).Methods("GET")
Expand Down
69 changes: 69 additions & 0 deletions managers/SyncManager.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"math/rand"
"sort"
"strconv"
"strings"
"time"

"github.com/CalebRose/SimFBA/dbprovider"
Expand Down Expand Up @@ -1191,6 +1192,74 @@ func getRecruitingOdds(ts structs.Timestamp, croot structs.Recruit, team structs
}
}

func AllocateAIRedshirts(seasonId string) {
allAICollegeTeams := GetAllAvailableCollegeTeams()
seasonStatsMap := GetCFBPlayerSeasonStatMapBySeason(seasonId, "2")

for _, team := range allAICollegeTeams {
log.Printf("\nAllocating redshirts for %s\n", team.TeamAbbr)
redshirtTargets := GetAllCollegePlayersByTeamId(strconv.Itoa(int(team.ID)))
positionCountMap := getPositionCounts(redshirtTargets)

redshirtCount := 0
redshirts := make([]string, 20)
for _, target := range redshirtTargets {
if redshirtCount >= 20 {
break
}

playerSeasonStats := seasonStatsMap[uint(target.PlayerID)]

/*
* Redshirt top 20 players that have never been redshirted and either have no snaps or a long-term injury this season.
* Also skips players if redshirting would put the team below that position minimum.
* GetAllCollegePlayersByTeamId returns players sorted by OVR by default.
*/
if (playerSeasonStats.GamesPlayed == 0 ||
(target.InjuryType != "" && target.WeeksOfRecovery >= 10)) &&
!target.IsRedshirt && !target.IsRedshirting &&
isAboveMinPositionCount(target.Position, positionCountMap) {

redshirts[redshirtCount] = fmt.Sprintf("%s %s %s %s, GamesPlayed: %d, Injury Weeks: %d\n", team.TeamAbbr, target.Position, target.FirstName, target.LastName, playerSeasonStats.GamesPlayed, target.WeeksOfRecovery)
SetRedshirtStatusForPlayer(strconv.Itoa(target.TeamID))
positionCountMap[target.Position] -= 1
redshirtCount++
}
}
log.Printf("Redshirts for %s:\n%s\n", team.TeamAbbr, strings.Join(redshirts, ""))
}
}

func getPositionCounts(players []structs.CollegePlayer) map[string]int {
counts := make(map[string]int)
for _, player := range players {
counts[player.Position]++
}
return counts
}

func isAboveMinPositionCount(position string, positionCountMap map[string]int) bool {
minPositionThreshold := 0;

switch position {
case "ATH":
minPositionThreshold = 0
case "P", "K":
minPositionThreshold = 1
case "QB", "RB", "FB", "TE", "FS", "SS", "C":
minPositionThreshold = 3
case "OT", "OG", "DE", "DT", "OLB", "ILB":
minPositionThreshold = 4
case "WR", "CB":
minPositionThreshold = 5
default:
panic(fmt.Sprintf("Invalid position %s found in redshirt logic", position))
}

positionCount := positionCountMap[position]
return positionCount > minPositionThreshold
}

func getCoachMap() map[uint]structs.CollegeCoach {
coachMap := make(map[uint]structs.CollegeCoach)

Expand Down
Loading