feat: target rating calculator (required round average for N rounds) #2
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Beskrivning
Lägg till en funktion där användaren anger en önskad rating och antal rundor (t.ex. 930 på 4 rundor), och systemet räknar ut vilket snitt spelaren behöver gå på dessa rundor för att hamna på targetratingen efter nästa officiella PDGA-uträkning.
Detta är en naturlig förlängning av befintlig "Predicted rating"-funktion: istället för att förutsäga resultatet av nuvarande historik, inverterar vi formeln för att hitta vilka framtida rundor som krävs för ett önskat resultat.
Design
Placering: Ny ikon/knapp i
views/partials/ratings-table.ejsbredvid Predicted-kolumnen (samma rad somshowDebugInfo-ikonen). Knappen öppnar en modal — återanvänd modal-mönstret som redan finns ipublic/js/players.jsför debug-info.Modal-innehåll:
930)XXX rating(det enda krävda värdet)<current>till<target>på<N>rundor behöver du snittaXXXpå dessa rundor (beräknat enligt PDGA:s officiella uträkning för nästa publicering)."XXX > 1050(PDGA top-100-nivå) ellerXXX < 600, visa varning: "⚠️ Detta är ett extremt värde — kontrollera att din target är rimlig."Layout: Återanvänd
.card-section+.modalCSS från befintliga modaler.Tekniska noteringar
Backend
Ny endpoint:
POST /api/calculate-target-rating/:pdgaNumberisrc/routes/players.jsRequest body:
{ targetRating: number, rounds: number }Response:
{ requiredAverage: number, currentRating: number, predictedRating: number, warning?: string }Ny funktion i
src/services/rating-calculator.js:Implementation: binärsökning över kandidatratings R i intervallet
[400, 1200]. För varje R:simulatedRounds = roundRatings ∪ [{ rating: R, date: <just före next PDGA-update>, competition: 'simulated' } × numRounds]calculatePredictedRating(simulatedRounds)— den hanterar redan PDGA-cutoff, outlier-borttagning och dubbelviktning korrektratingmottargetRating|predicted - target| < 0.5Datum för simulerade rundor sätts till
getNextPDGAUpdateDate() - 1 dagså de räknas in i nästa publicering.Varför binärsökning: Outlier-removal (≥7 rundor) och dubbelviktning (≥9 rundor) gör formeln icke-linjär i R. Binärsökning är ~20 iterationer av en cheap funktion — försumbar kostnad jämfört med en closed-form-lösning som måste specialfalla varje gren.
Edge cases att hantera:
[400, 1200]): returnera närmaste gräns + warningFrontend
Ny fil: lägg till handler i
public/js/players.js(eller bryt ut till nypublic/js/target-rating.jsom det blir >100 rader):openTargetRatingModal(pdgaNumber)— öppnar modalen, läser nuvarande ratingcalculateTargetRating(pdgaNumber)—fetchtill nya endpointen, renderar resultatMall: Lägg modal-markup i
views/partials/target-rating-modal.ejs(ny partial), include:a frånviews/pages/index.ejs.HTMX vs vanilla fetch: Befintlig modal-logik (
showDebugInfo) använder vanilla fetch + DOM-manipulation. Följ samma mönster för konsistens.Databas
Inga schema-ändringar behövs — beräkningen är stateless, vi cachar inte target-resultat (de är cheap att räkna om vid varje input-ändring).
Scope
Ingår:
Ingår inte (möjliga uppföljningar):
±X ratingpå snittet — kan vara nyttigt men över-engineering för v1)