package recommendation import ( "sort" "time" "git.fabledsword.com/bvandeusen/minstrel/internal/db/dbq" ) // Candidate pairs a track with the inputs needed to score it. type Candidate struct { Track dbq.Track Inputs ScoringInputs } // Shuffle scores each candidate, sorts descending by score, and returns // the top `limit` candidates. limit <= 0 returns nil; nil input returns // nil. Pure — no IO, no global state beyond the rng callback. func Shuffle( candidates []Candidate, weights ScoringWeights, now time.Time, rng func() float64, limit int, ) []Candidate { if len(candidates) == 0 || limit <= 0 { return nil } scored := make([]struct { c Candidate score float64 }, len(candidates)) for i, c := range candidates { scored[i].c = c scored[i].score = Score(c.Inputs, weights, now, rng) } sort.Slice(scored, func(i, j int) bool { return scored[i].score > scored[j].score }) if limit > len(scored) { limit = len(scored) } out := make([]Candidate, limit) for i := 0; i < limit; i++ { out[i] = scored[i].c } return out }