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>
|
||||
A perfect run inside {OPORD_DIFFICULTIES[difficulty].parTimeMs / 1000}s earns a{" "}
|
||||
{OPORD_DIFFICULTIES[difficulty].perfectBonus}-point bonus. Each tier tracks its own
|
||||
best score.
|
||||
{OPORD_DIFFICULTIES[difficulty].perfectBonus}-point bonus. Finishing under the par
|
||||
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>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,12 @@ export interface OpordTierConfig {
|
|||
readonly parTimeMs: number;
|
||||
/** Bonus for a perfect run inside the par time. */
|
||||
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. */
|
||||
|
|
@ -50,6 +56,7 @@ export const OPORD_DIFFICULTIES: Record<OpordDifficulty, OpordTierConfig> = {
|
|||
correctPoints: 100,
|
||||
parTimeMs: 100_000,
|
||||
perfectBonus: 150,
|
||||
maxSpeedBonus: 150,
|
||||
},
|
||||
veteran: {
|
||||
studyHintSeconds: 25,
|
||||
|
|
@ -58,6 +65,7 @@ export const OPORD_DIFFICULTIES: Record<OpordDifficulty, OpordTierConfig> = {
|
|||
correctPoints: 150,
|
||||
parTimeMs: 150_000,
|
||||
perfectBonus: 300,
|
||||
maxSpeedBonus: 250,
|
||||
},
|
||||
elite: {
|
||||
// Extra clock headroom: elite relational questions include time arithmetic.
|
||||
|
|
@ -67,6 +75,7 @@ export const OPORD_DIFFICULTIES: Record<OpordDifficulty, OpordTierConfig> = {
|
|||
correctPoints: 200,
|
||||
parTimeMs: 200_000,
|
||||
perfectBonus: 500,
|
||||
maxSpeedBonus: 400,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -103,7 +112,15 @@ export function calculateOpordScore(
|
|||
): number {
|
||||
const tier = OPORD_DIFFICULTIES[difficulty];
|
||||
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 {
|
||||
|
|
|
|||
Loading…
Reference in a new issue