diff --git a/react/src/quiz/quiz-result.tsx b/react/src/quiz/quiz-result.tsx
index eeab595f..75b5af90 100644
--- a/react/src/quiz/quiz-result.tsx
+++ b/react/src/quiz/quiz-result.tsx
@@ -113,12 +113,7 @@ export function QuizResult(props: QuizResultProps): ReactNode {
: undefined
}
- {
- // TODO stats for infinite quiz
- props.quizDescriptor.kind === 'custom' || props.quizDescriptor.kind === 'infinite'
- ? undefined
- :
- }
+
Details (spoilers, don't share!)
@@ -477,7 +472,7 @@ export function GenericQuizResultRow(props: GenericQuizResultRowProps): ReactNod
{props.getStat('a')}
|
-
+ |
{comparison}
|
diff --git a/react/src/quiz/quiz-statistics.tsx b/react/src/quiz/quiz-statistics.tsx
index 4c2620e0..fcf31a41 100644
--- a/react/src/quiz/quiz-statistics.tsx
+++ b/react/src/quiz/quiz-statistics.tsx
@@ -2,16 +2,32 @@ import React, { ReactNode } from 'react'
import { useColors, useJuxtastatColors } from '../page_template/colors'
-import { QuizDescriptorWithTime, QuizHistory } from './quiz'
-import { parseTimeIdentifier } from './statistics'
+import { QuizDescriptor, QuizDescriptorWithTime, QuizHistory } from './quiz'
+import { getInfiniteQuizzes, parseTimeIdentifier } from './statistics'
-interface QuizStatisticsProps {
- // this kind of statistic only really applies to daily/weekly quizzes
- quiz: QuizDescriptorWithTime
- wholeHistory: QuizHistory
+export function QuizStatistics(
+ props: {
+ quiz: QuizDescriptor
+ wholeHistory: QuizHistory
+ },
+): ReactNode | undefined {
+ switch (props.quiz.kind) {
+ case 'juxtastat':
+ case 'retrostat':
+ return
+ case 'infinite':
+ return
+ case 'custom':
+ return undefined
+ }
}
-export function QuizStatistics(props: QuizStatisticsProps): ReactNode {
+export function QuizStatisticsForTimedStatistics(
+ props: {
+ quiz: QuizDescriptorWithTime
+ wholeHistory: QuizHistory
+ },
+): ReactNode {
const colors = useColors()
const history = (i: number): QuizHistory[string] | undefined => {
switch (props.quiz.kind) {
@@ -153,3 +169,31 @@ export function DisplayedStat({ number, name, additionalClass, color }: { number
)
}
+
+export function QuizStatisticsForInfinite(
+ props: {
+ quiz: QuizDescriptor & { kind: 'infinite' }
+ wholeHistory: QuizHistory
+ },
+): ReactNode | undefined {
+ const [seedVersions, keys] = getInfiniteQuizzes(props.wholeHistory)
+ const numCorrects = keys.map(
+ key => props.wholeHistory[key].correct_pattern.reduce((partialSum: number, a) => partialSum + (a ? 1 : 0), 0),
+ )
+
+ // sort indices by numCorrects
+ let sortedIndices = Array.from(Array(numCorrects.length).keys())
+ sortedIndices.sort((a, b) => numCorrects[a] - numCorrects[b])
+ // take first 5
+ sortedIndices = sortedIndices.slice(0, 5)
+ if (sortedIndices.length === 0) {
+ return undefined
+ }
+
+ const sortedSeedVersions = sortedIndices.map(i => seedVersions[i])
+ const sortedNumCorrects = sortedIndices.map(i => numCorrects[i])
+
+ console.log(sortedSeedVersions)
+ console.log(sortedNumCorrects)
+ return undefined
+}
diff --git a/react/src/quiz/statistics.ts b/react/src/quiz/statistics.ts
index f83d6ca0..8c54a55b 100644
--- a/react/src/quiz/statistics.ts
+++ b/react/src/quiz/statistics.ts
@@ -50,7 +50,7 @@ async function reportToServerGeneric(wholeHistory: QuizHistory, endpointLatest:
return false
}
-function getInfiniteQuizzes(wholeHistory: QuizHistory): [[string, number][], string[]] {
+export function getInfiniteQuizzes(wholeHistory: QuizHistory): [[string, number][], string[]] {
const seedVersions: [string, number][] = []
const keys: string[] = []
for (const day of Object.keys(wholeHistory)) {
diff --git a/react/test/quiz_infinite_test.ts b/react/test/quiz_infinite_test.ts
index 2a0c8843..021204af 100644
--- a/react/test/quiz_infinite_test.ts
+++ b/react/test/quiz_infinite_test.ts
@@ -33,44 +33,94 @@ async function correctIncorrect(t: TestController): Promise {
const localStorageDefault = { persistent_id: '000000000000007', secure_id: '00000003' }
-async function completeCorrectAnswerSequence(t: TestController, alreadyKnownAnswers: string[]): Promise {
+const seedStr = 'deadbeef00'
+
+// async function completeCorrectAnswerSequence(t: TestController, alreadyKnownAnswers: string[]): Promise {
+// // console.log(await sampleRandomQuestion(seedStr, 0))
+// await t.eval(() => {
+// localStorage.clear()
+// for (const key of Object.keys(localStorageDefault)) {
+// localStorage.setItem(key, localStorageDefault[key])
+// }
+// }, { dependencies: { localStorageDefault } })
+// await t.wait(100)
+// await safeReload(t)
+// await waitForQuizLoading(t)
+// await clickButtons(t, alreadyKnownAnswers)
+// while (await isQuestionPage(t)) {
+// await clickButton(t, 'a')
+// await t.wait(500)
+// }
+// // check that the first n characters match the already known answers
+// const text = await correctIncorrect(t)
+// for (let i = 0; i < alreadyKnownAnswers.length; i++) {
+// if (!text[i]) {
+// throw new Error('alreadyKnownAnswers is incorrect')
+// }
+// }
+// const correctAnswers: string[] = [...alreadyKnownAnswers]
+// for (let i = alreadyKnownAnswers.length; i < text.length; i++) {
+// if (text[i]) {
+// correctAnswers.push('a')
+// }
+// else {
+// correctAnswers.push('b')
+// }
+// }
+// // check that the prefixes match
+
+// return correctAnswers
+// }
+
+const correctAnswerSequences = new Map()
+
+quizFixture(
+ 'collect correct answers',
+ `${target}/quiz.html`,
+ localStorageDefault,
+ ``,
+ 'desktop',
+)
+
+const version = 0
+
+test('collect correct answers', async (t) => {
+ const seed = 'deadbeef00'
+ // set localStorage such that I_{seedStr}_{version} has had 30 questions answered
await t.eval(() => {
- localStorage.clear()
- for (const key of Object.keys(localStorageDefault)) {
- localStorage.setItem(key, localStorageDefault[key])
- }
- }, { dependencies: { localStorageDefault } })
- await t.wait(100)
+ localStorage.quiz_history = JSON.stringify({
+ [`I_${seed}_${version}`]: {
+ // false so the quiz ends
+ correct_pattern: Array(30).fill(false),
+ choices: Array(30).fill('a'),
+ },
+ })
+ }, { dependencies: { seed, version } })
+ await t.navigateTo(`${target}/quiz.html#mode=infinite&seed=${seed}&v=${version}`)
await safeReload(t)
- await waitForQuizLoading(t)
- await clickButtons(t, alreadyKnownAnswers)
- while (await isQuestionPage(t)) {
- await clickButton(t, 'a')
- await t.wait(500)
- }
- // check that the first n characters match the already known answers
- const text = await correctIncorrect(t)
- for (let i = 0; i < alreadyKnownAnswers.length; i++) {
- if (!text[i]) {
- throw new Error('alreadyKnownAnswers is incorrect')
- }
- }
- const correctAnswers: string[] = [...alreadyKnownAnswers]
- for (let i = alreadyKnownAnswers.length; i < text.length; i++) {
- if (text[i]) {
+ // Get all quiz_result_symbol elements and the text therein
+ const symbols = Selector('.quiz_result_comparison_symbol')
+ const symbolsCount = await symbols.count
+ const correctAnswers: string[] = []
+ for (let i = 0; i < symbolsCount; i++) {
+ const symbol = symbols.nth(i)
+ const text = await symbol.innerText
+ console.log(text)
+ if (text === '>') {
correctAnswers.push('a')
}
- else {
+ else if (text === '<') {
correctAnswers.push('b')
}
+ else {
+ throw new Error(`unexpected text ${text} in ${await symbol.textContent}`)
+ }
}
- // check that the prefixes match
-
- return correctAnswers
-}
+ correctAnswerSequences.set(seed, correctAnswers)
+})
const seed = 0xdeadbeef00
-const param = '#mode=infinite&seed=deadbeef00&v=0'
+const param = `#mode=infinite&seed=${seedStr}&v=${version}`
quizFixture(
'generate link',
`${target}/quiz.html${param}`,
@@ -79,21 +129,22 @@ quizFixture(
'desktop',
)
-let correctAnswerSequence: string[]
+// let correctAnswerSequence: string[]
-test('formulates correct sequence', async (t) => {
- // returns if quiztext exists as a class
- let alreadyKnownAnswers: string[] = []
- while (true) {
- alreadyKnownAnswers = await completeCorrectAnswerSequence(t, alreadyKnownAnswers)
- if (alreadyKnownAnswers.length >= 30) {
- break
- }
- }
- correctAnswerSequence = alreadyKnownAnswers
-})
+// test('formulates correct sequence', async (t) => {
+// // returns if quiztext exists as a class
+// let alreadyKnownAnswers: string[] = []
+// while (true) {
+// alreadyKnownAnswers = await completeCorrectAnswerSequence(t, alreadyKnownAnswers)
+// if (alreadyKnownAnswers.length >= 30) {
+// break
+// }
+// }
+// correctAnswerSequence = alreadyKnownAnswers
+// })
async function provideAnswers(t: TestController, start: number, isCorrect: boolean[]): Promise {
+ const correctAnswerSequence = correctAnswerSequences.get(seedStr)!
for (let i = start; i < start + isCorrect.length; i++) {
await clickButton(t, isCorrect[i - start] === (correctAnswerSequence[i] === 'a') ? 'a' : 'b')
await t.wait(500)
@@ -184,3 +235,7 @@ test('19-correct', async (t) => {
// low bit order first: 1111,1111 1111,1111 1111,0000 000[0,0000] This becomes FF FF 0F 00
await t.expect(await juxtastatInfiniteTable()).eql(`7|${seed}|FFFF0F00|20|27\n`)
})
+
+// test('do-not-report-partial', async (t) => {
+// await provideAnswers(t, 0, [false, true, true, true, true])
+// await t.navigateTo(`${target}/quiz.html#mode=infinite&seed=deadbeef01&v=0`)
|