feat(opord): add par-anchored speed bonus to scoring
This commit is contained in:
parent
181f244f62
commit
eb77f45b95
2 changed files with 21 additions and 3 deletions
|
|
@ -150,8 +150,9 @@ export function OpordArena({
|
||||||
<span className="font-medium text-foreground">Debrief</span>
|
<span className="font-medium text-foreground">Debrief</span>
|
||||||
<span>
|
<span>
|
||||||
A perfect run inside {OPORD_DIFFICULTIES[difficulty].parTimeMs / 1000}s earns a{" "}
|
A perfect run inside {OPORD_DIFFICULTIES[difficulty].parTimeMs / 1000}s earns a{" "}
|
||||||
{OPORD_DIFFICULTIES[difficulty].perfectBonus}-point bonus. Each tier tracks its own
|
{OPORD_DIFFICULTIES[difficulty].perfectBonus}-point bonus. Finishing under the par
|
||||||
best score.
|
time also earns a speed bonus that scales with how fast you finish and how many
|
||||||
|
answers you got right. Each tier tracks its own best score.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,12 @@ export interface OpordTierConfig {
|
||||||
readonly parTimeMs: number;
|
readonly parTimeMs: number;
|
||||||
/** Bonus for a perfect run inside the par time. */
|
/** Bonus for a perfect run inside the par time. */
|
||||||
readonly perfectBonus: number;
|
readonly perfectBonus: number;
|
||||||
|
/**
|
||||||
|
* Points pool for the time bonus: a run finishing under the par time earns
|
||||||
|
* this scaled by the fraction of par time saved and the fraction of
|
||||||
|
* questions answered correctly, so speed pays only alongside accuracy.
|
||||||
|
*/
|
||||||
|
readonly maxSpeedBonus: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Grace added to the quiz limit for network/rounding before the server rejects. */
|
/** Grace added to the quiz limit for network/rounding before the server rejects. */
|
||||||
|
|
@ -50,6 +56,7 @@ export const OPORD_DIFFICULTIES: Record<OpordDifficulty, OpordTierConfig> = {
|
||||||
correctPoints: 100,
|
correctPoints: 100,
|
||||||
parTimeMs: 100_000,
|
parTimeMs: 100_000,
|
||||||
perfectBonus: 150,
|
perfectBonus: 150,
|
||||||
|
maxSpeedBonus: 150,
|
||||||
},
|
},
|
||||||
veteran: {
|
veteran: {
|
||||||
studyHintSeconds: 25,
|
studyHintSeconds: 25,
|
||||||
|
|
@ -58,6 +65,7 @@ export const OPORD_DIFFICULTIES: Record<OpordDifficulty, OpordTierConfig> = {
|
||||||
correctPoints: 150,
|
correctPoints: 150,
|
||||||
parTimeMs: 150_000,
|
parTimeMs: 150_000,
|
||||||
perfectBonus: 300,
|
perfectBonus: 300,
|
||||||
|
maxSpeedBonus: 250,
|
||||||
},
|
},
|
||||||
elite: {
|
elite: {
|
||||||
// Extra clock headroom: elite relational questions include time arithmetic.
|
// Extra clock headroom: elite relational questions include time arithmetic.
|
||||||
|
|
@ -67,6 +75,7 @@ export const OPORD_DIFFICULTIES: Record<OpordDifficulty, OpordTierConfig> = {
|
||||||
correctPoints: 200,
|
correctPoints: 200,
|
||||||
parTimeMs: 200_000,
|
parTimeMs: 200_000,
|
||||||
perfectBonus: 500,
|
perfectBonus: 500,
|
||||||
|
maxSpeedBonus: 400,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -103,7 +112,15 @@ export function calculateOpordScore(
|
||||||
): number {
|
): number {
|
||||||
const tier = OPORD_DIFFICULTIES[difficulty];
|
const tier = OPORD_DIFFICULTIES[difficulty];
|
||||||
const perfect = correct >= tier.questionCount && timeMs <= tier.parTimeMs;
|
const perfect = correct >= tier.questionCount && timeMs <= tier.parTimeMs;
|
||||||
return Math.max(0, correct * tier.correctPoints + (perfect ? tier.perfectBonus : 0));
|
const speedBonus =
|
||||||
|
timeMs < tier.parTimeMs
|
||||||
|
? Math.round(
|
||||||
|
((tier.parTimeMs - timeMs) / tier.parTimeMs) *
|
||||||
|
tier.maxSpeedBonus *
|
||||||
|
(correct / tier.questionCount),
|
||||||
|
)
|
||||||
|
: 0;
|
||||||
|
return Math.max(0, correct * tier.correctPoints + speedBonus + (perfect ? tier.perfectBonus : 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateOpordXp(score: number, isNewTierBest: boolean): number {
|
export function calculateOpordXp(score: number, isNewTierBest: boolean): number {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue