From a3765b9b52f792d4660979a5b93fd967295b736f Mon Sep 17 00:00:00 2001 From: Miodec Date: Sun, 9 Nov 2025 09:54:29 +0100 Subject: [PATCH] fix: partially correct last words counting towards final wpm in non timed modes --- frontend/src/ts/test/test-logic.ts | 2 +- frontend/src/ts/test/test-stats.ts | 26 +++++++++++++++++++------- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/frontend/src/ts/test/test-logic.ts b/frontend/src/ts/test/test-logic.ts index 0a4780b2b..d92e2af0d 100644 --- a/frontend/src/ts/test/test-logic.ts +++ b/frontend/src/ts/test/test-logic.ts @@ -967,7 +967,7 @@ export async function finish(difficultyFailed = false): Promise { } // stats - const stats = TestStats.calculateStats(); + const stats = TestStats.calculateFinalStats(); if (stats.time % 1 !== 0 && Config.mode !== "time") { TestStats.setLastSecondNotRound(); } diff --git a/frontend/src/ts/test/test-stats.ts b/frontend/src/ts/test/test-stats.ts index e00f151b8..5246d2ebf 100644 --- a/frontend/src/ts/test/test-stats.ts +++ b/frontend/src/ts/test/test-stats.ts @@ -7,6 +7,7 @@ import * as TestState from "./test-state"; import * as Numbers from "@monkeytype/util/numbers"; import { CompletedEvent, IncompleteTest } from "@monkeytype/schemas/results"; import { isFunboxActiveWithProperty } from "./funbox/list"; +import * as CustomText from "./custom-text"; type CharCount = { spaces: number; @@ -144,14 +145,17 @@ export function calculateTestSeconds(now?: number): number { } } -export function calculateWpmAndRaw(withDecimalPoints?: true): { +export function calculateWpmAndRaw( + withDecimalPoints?: true, + final = false +): { wpm: number; raw: number; } { const testSeconds = calculateTestSeconds( TestState.isActive ? performance.now() : end ); - const chars = countChars(); + const chars = countChars(final); const wpm = Numbers.roundTo2( ((chars.correctWordChars + chars.correctSpaces) * (60 / testSeconds)) / 5 ); @@ -280,7 +284,7 @@ function getTargetWords(): string[] { return targetWords; } -function countChars(): CharCount { +function countChars(final = false): CharCount { let correctWordChars = 0; let correctChars = 0; let incorrectChars = 0; @@ -343,7 +347,13 @@ function countChars(): CharCount { } correctChars += toAdd.correct; incorrectChars += toAdd.incorrect; - if (i === inputWords.length - 1) { + + const isTimedTest = + Config.mode === "time" || + (Config.mode === "custom" && CustomText.getLimit().mode === "time"); + const shouldCountPartialLastWord = !final || (final && isTimedTest); + + if (i === inputWords.length - 1 && shouldCountPartialLastWord) { //last word - check if it was all correct - add to correct word chars if (toAdd.incorrect === 0) correctWordChars += toAdd.correct; } else { @@ -370,7 +380,7 @@ function countChars(): CharCount { }; } -export function calculateStats(): Stats { +export function calculateFinalStats(): Stats { console.debug("Calculating result stats"); let testSeconds = calculateTestSeconds(); console.debug( @@ -398,8 +408,10 @@ export function calculateStats(): Stats { testSeconds ); } - const chars = countChars(); - const { wpm, raw } = calculateWpmAndRaw(true); + + //todo: this counts chars twice - once here and once in calculateWpmAndRaw + const chars = countChars(true); + const { wpm, raw } = calculateWpmAndRaw(true, true); const acc = Numbers.roundTo2(calculateAccuracy()); const ret = { wpm: isNaN(wpm) ? 0 : wpm,