diff --git a/Frontend/src/lib/solveTime.ts b/Frontend/src/lib/solveTime.ts new file mode 100644 index 00000000..9c78c472 --- /dev/null +++ b/Frontend/src/lib/solveTime.ts @@ -0,0 +1,120 @@ +import { EventId, getEventResultType } from '@wca/helpers' + +export const SECOND_IN_CS = 100 +export const MINUTE_IN_CS = 60 * SECOND_IN_CS +export const HOUR_IN_CS = 60 * MINUTE_IN_CS + +interface PluralizeParams { + count: number + word: string + options?: { + fixed?: number + abbreviate?: boolean + } +} + +export function pluralize({ count, word, options = {} }: PluralizeParams) { + const countStr = + options.fixed && count % 1 > 0 ? count.toFixed(options.fixed) : count + const countDesc = options.abbreviate + ? word[0] + : ` ${count === 1 ? word : `${word}s`}` + return countStr + countDesc +} + +interface AttemptResultToStringParams { + attemptResult: number + eventId: EventId +} + +export function attemptResultToString({ + attemptResult, + eventId, +}: AttemptResultToStringParams) { + const type = getEventResultType(eventId) + if (type === 'time') { + return centiSecondsToHumanReadable({ c: attemptResult }) + } + if (type === 'number') { + return `${attemptResult} moves` + } + return `${attemptResultToMbPoints(attemptResult)} points` +} + +function parseMbValue(val: number) { + let mbValue = val + const old = Math.floor(mbValue / 1000000000) !== 0 + let timeSeconds + let attempted + let solved + if (old) { + timeSeconds = mbValue % 100000 + mbValue = Math.floor(mbValue / 100000) + attempted = mbValue % 100 + mbValue = Math.floor(mbValue / 100) + solved = 99 - (mbValue % 100) + } else { + const missed = mbValue % 100 + mbValue = Math.floor(mbValue / 100) + timeSeconds = mbValue % 100000 + mbValue = Math.floor(mbValue / 100000) + const difference = 99 - (mbValue % 100) + + solved = difference + missed + attempted = solved + missed + } + + const timeCentiseconds = timeSeconds === 99999 ? null : timeSeconds * 100 + return { solved, attempted, timeCentiseconds } +} + +function attemptResultToMbPoints(mbValue: number) { + const { solved, attempted } = parseMbValue(mbValue) + const missed = attempted - solved + return solved - missed +} + +interface CentiSecondsToHumanReadableParams { + c: number + options?: { + short?: boolean + } +} +export function centiSecondsToHumanReadable({ + c, + options = {}, +}: CentiSecondsToHumanReadableParams) { + let centiseconds = c + let str = '' + + const hours = centiseconds / HOUR_IN_CS + centiseconds %= HOUR_IN_CS + if (hours >= 1) { + str += `${pluralize({ + count: Math.floor(hours), + word: 'hour', + options: { abbreviate: options.short }, + })} ` + } + + const minutes = centiseconds / MINUTE_IN_CS + centiseconds %= MINUTE_IN_CS + if (minutes >= 1) { + str += `${pluralize({ + count: Math.floor(minutes), + word: 'minute', + options: { abbreviate: options.short }, + })} ` + } + + const seconds = centiseconds / SECOND_IN_CS + if (seconds > 0 || str.length === 0) { + str += `${pluralize({ + count: seconds, + word: 'second', + options: { fixed: 2, abbreviate: options.short }, + })} ` + } + + return str.trim() +} diff --git a/Frontend/src/pages/events/index.jsx b/Frontend/src/pages/events/index.jsx index 09c3a3c2..a485558c 100644 --- a/Frontend/src/pages/events/index.jsx +++ b/Frontend/src/pages/events/index.jsx @@ -13,6 +13,10 @@ import { } from 'semantic-ui-react' import getCompetitionWcif from '../../api/competition/get/get_competition_wcif' import { CompetitionContext } from '../../api/helper/context/competition_context' +import { + attemptResultToString, + centiSecondsToHumanReadable, +} from '../../lib/solveTime' import { setMessage } from '../../ui/events/messages' import LoadingMessage from '../../ui/messages/loadingMessage' @@ -73,12 +77,17 @@ export default function Events() { {getFormatName(round.format)} {round.timeLimit && - `${round.timeLimit.centiseconds / 100} seconds`} + centiSecondsToHumanReadable({ + c: round.timeLimit.centiseconds, + })} {competitionInfo['uses_cutoff?'] && ( {round.cutoff && - `${round.cutoff?.attemptResult / 100} seconds`} + attemptResultToString({ + attemptResult: round.cutoff.attemptResult, + eventId: event.id, + })} )}