feat: show sensitivity bracket around required average
After the binary search converges, also simulate predicted rating at required±1 average. Display the three rows in the modal so the user can see how sharp the requirement is — e.g. whether averaging 1 point lower costs them 1 point of predicted rating or 5.
This commit is contained in:
@@ -495,7 +495,8 @@ router.post('/api/calculate-target-rating/:pdgaNumber', async (req, res) => {
|
||||
requiredAverage: result.requiredAverage,
|
||||
predictedRating: result.simulatedPredicted,
|
||||
warning: result.warning,
|
||||
iterations: result.iterations
|
||||
iterations: result.iterations,
|
||||
sensitivity: result.sensitivity
|
||||
});
|
||||
} catch (err) {
|
||||
logger.error(`Target rating calc failed for PDGA ${pdgaNum}: ${err.message}`);
|
||||
|
||||
@@ -58,6 +58,14 @@ function calculateRequiredAverage(roundRatings, targetRating, numRounds) {
|
||||
warning = 'Could not converge precisely; result is approximate.';
|
||||
}
|
||||
|
||||
const lowerAvg = Math.max(400, Math.round((requiredAverage - 1) * 10) / 10);
|
||||
const upperAvg = Math.min(1200, Math.round((requiredAverage + 1) * 10) / 10);
|
||||
const sensitivity = {
|
||||
lower: { average: lowerAvg, predicted: simulate(lowerAvg) },
|
||||
target: { average: requiredAverage, predicted: simulatedPredicted },
|
||||
upper: { average: upperAvg, predicted: simulate(upperAvg) }
|
||||
};
|
||||
|
||||
logger.debug(`Target rating calc: target=${targetRating} rounds=${numRounds} → avg=${requiredAverage} (iterations=${iterations}, simulated=${simulatedPredicted})`);
|
||||
|
||||
return {
|
||||
@@ -65,7 +73,8 @@ function calculateRequiredAverage(roundRatings, targetRating, numRounds) {
|
||||
currentPredicted,
|
||||
simulatedPredicted,
|
||||
iterations,
|
||||
warning
|
||||
warning,
|
||||
sensitivity
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user