|
|
|
@@ -113,12 +113,15 @@ export function scoreRound(
|
|
|
|
|
let scoreA: number
|
|
|
|
|
let scoreB: number
|
|
|
|
|
|
|
|
|
|
let resultType: 'both-correct' | 'one-correct' | 'both-wrong' = 'one-correct'
|
|
|
|
|
|
|
|
|
|
if (challenge.answers && challenge.answers.length > 0) {
|
|
|
|
|
// === FACTUAL SCORING ===
|
|
|
|
|
const correctA = checkAnswer(responseA.answer, challenge.answers)
|
|
|
|
|
const correctB = checkAnswer(responseB.answer, challenge.answers)
|
|
|
|
|
|
|
|
|
|
if (correctA > 0 && correctB > 0) {
|
|
|
|
|
resultType = 'both-correct'
|
|
|
|
|
// Both correct -- speed is tiebreaker
|
|
|
|
|
const faster = Math.min(responseA.timeMs, responseB.timeMs)
|
|
|
|
|
const slower = Math.max(responseA.timeMs, responseB.timeMs)
|
|
|
|
@@ -143,12 +146,14 @@ export function scoreRound(
|
|
|
|
|
scoreB = ONE_CORRECT_WINNER_BASE + correctB * CONFIDENCE_BONUS
|
|
|
|
|
} else {
|
|
|
|
|
// Both wrong -- speed tiebreaker in low range
|
|
|
|
|
resultType = 'both-wrong'
|
|
|
|
|
const aFaster = responseA.timeMs <= responseB.timeMs
|
|
|
|
|
scoreA = aFaster ? BOTH_WRONG_FASTER : BOTH_WRONG_SLOWER
|
|
|
|
|
scoreB = aFaster ? BOTH_WRONG_SLOWER : BOTH_WRONG_FASTER
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// No answers defined — both get base score (all challenges should be factual)
|
|
|
|
|
resultType = 'both-wrong'
|
|
|
|
|
scoreA = 3
|
|
|
|
|
scoreB = 3
|
|
|
|
|
}
|
|
|
|
@@ -169,7 +174,7 @@ export function scoreRound(
|
|
|
|
|
const loserDamage = Math.max(0, challenge.baseDamage * LOSER_DAMAGE_BASE - margin)
|
|
|
|
|
|
|
|
|
|
const narration = winnerId
|
|
|
|
|
? generateNarration(challenge, winnerName!, loserName!, margin, isCritical)
|
|
|
|
|
? generateNarration(challenge, winnerName!, loserName!, margin, isCritical, resultType)
|
|
|
|
|
: pick([
|
|
|
|
|
`Dead even! ${botA.name} and ${botB.name} are perfectly matched. Like two politicians blaming each other.`,
|
|
|
|
|
`IT'S A TIE! ${botA.name} and ${botB.name} cancel each other out like Congress!`,
|
|
|
|
@@ -230,10 +235,26 @@ function generateNarration(
|
|
|
|
|
loser: string,
|
|
|
|
|
margin: number,
|
|
|
|
|
isCritical: boolean,
|
|
|
|
|
resultType: 'both-correct' | 'one-correct' | 'both-wrong' = 'one-correct',
|
|
|
|
|
): string {
|
|
|
|
|
const critPrefix = isCritical ? 'CRITICAL HIT! ' : ''
|
|
|
|
|
const isFactual = challenge.scoring === 'factual'
|
|
|
|
|
|
|
|
|
|
// Both bots got it WRONG — narration must reflect that
|
|
|
|
|
if (isFactual && resultType === 'both-wrong') {
|
|
|
|
|
const bothWrong = [
|
|
|
|
|
`${critPrefix}Both bots WHIFFED! Nobody got it right but ${winner} failed FASTER. Is that even a win?`,
|
|
|
|
|
`${critPrefix}DOUBLE MISS! ${winner} and ${loser} both got it wrong! ${winner} wins on speed alone. Participation trophy energy.`,
|
|
|
|
|
`${critPrefix}Two wrong answers! ${winner} was wrong FASTER than ${loser}. Speed isn't everything, but here we are.`,
|
|
|
|
|
`${critPrefix}Neither bot had a clue! ${winner} guessed quicker. ${loser} took their time being equally wrong.`,
|
|
|
|
|
`${critPrefix}BOTH WRONG! The only thing ${winner} beat ${loser} at was being wrong first. The crowd boos.`,
|
|
|
|
|
`${critPrefix}${winner} AND ${loser} both hallucinated! ${winner} at least hallucinated with conviction. Speed win.`,
|
|
|
|
|
`${critPrefix}NOBODY got the answer! ${winner} earns the world's saddest victory by responding faster. Tragic.`,
|
|
|
|
|
`${critPrefix}Wrong and wrong! ${winner} speedran being incorrect! ${loser} at least took time to think about it. Both failed.`,
|
|
|
|
|
]
|
|
|
|
|
return pick(bothWrong)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isFactual && margin > LARGE_WIN_MARGIN) {
|
|
|
|
|
const bigWins = [
|
|
|
|
|
`${critPrefix}${winner} NAILS IT! ${loser} didn't even come close. Embarrassing, honestly.`,
|
|
|
|
@@ -249,7 +270,7 @@ function generateNarration(
|
|
|
|
|
return pick(bigWins)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isFactual && margin <= CLOSE_MATCH_MARGIN) {
|
|
|
|
|
if (isFactual && resultType === 'both-correct' && margin <= CLOSE_MATCH_MARGIN) {
|
|
|
|
|
const closeOnes = [
|
|
|
|
|
`${critPrefix}Both bots got it right, but ${winner} was FASTER! ${loser} needs more coffee.`,
|
|
|
|
|
`${critPrefix}Correct on both sides! ${winner} edges it out by milliseconds. That's BRUTAL.`,
|
|
|
|
|