From 0fb73af58b59d433680206a9b00f5e0d14b367d6 Mon Sep 17 00:00:00 2001 From: lingdocs <71590811+lingdocs@users.noreply.github.com> Date: Tue, 12 Apr 2022 13:39:03 +0500 Subject: [PATCH] very beta quiz happening! --- package.json | 1 + src/components/np-picker/NPPicker.tsx | 4 +- src/components/vp-explorer/VPExplorer.tsx | 162 +++++++++++++++++----- src/lib/shuffle-array.ts | 24 ++++ src/library.ts | 2 + yarn.lock | 5 + 6 files changed, 161 insertions(+), 37 deletions(-) create mode 100644 src/lib/shuffle-array.ts diff --git a/package.json b/package.json index 23e27d0..a957a9c 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "classnames": "^2.2.6", "pbf": "^3.2.1", "rambda": "^6.7.0", + "react-rewards": "^2.0.3", "react-select": "^5.2.2" }, "devDependencies": { diff --git a/src/components/np-picker/NPPicker.tsx b/src/components/np-picker/NPPicker.tsx index 9e5b439..4e6c7c6 100644 --- a/src/components/np-picker/NPPicker.tsx +++ b/src/components/np-picker/NPPicker.tsx @@ -58,9 +58,9 @@ function NPPicker(props: { :
; return
{!npType &&
- {/*
+
Choose NP -
*/} +
{npTypes.map((npt) =>
- {(vps.verb && (mode === "quiz")) &&
- -
} - {(verbPhrase && ((mode === "phrases") || (mode === "quiz" && showAnswer))) && + {(verbPhrase && (mode === "phrases")) && } {(vps.verb && (mode === "charts")) && } + + {(mode === "quiz" && quizState) &&
+ {quizState.result === "waiting" ? <> +
Choose a correct answer:
+ {quizState.options.map(o =>
+
checkQuizAnswer(o)}> + {o} +
+
)} + :
+
❌ Wrong 😭
+
The correct answer was:
+ + {quizState.options.find(x => isInAnswer(x, quizState.answer)) as T.PsString} + +
+ +
+
} +
} {mode === "quiz" &&
{/* spacer for blank space while quizzing */}
} @@ -260,7 +296,63 @@ function switchSubjObj({ subject, verb }: T.VPSelectionState): T.VPSelectionStat }; } -function setRandomQuizState(mix: MixState) { +function makeQuizState(oldVps: T.VPSelectionState): { VPS: T.VPSelectionState, qs: QuizState } { + function makeRes(x: T.VPSelectionState) { + const y = completeVPSelection(x); + if (!y) { + throw new Error("trying to make a quiz out of an incomplete VPSelection") + } + return compileVP(renderVP(y), { removeKing: false, shrinkServant: false }); + } + const vps = getRandomVPSelection("both")(oldVps); + const wrongStates: T.VPSelectionState[] = []; + [1, 2, 3, 4].forEach(() => { + // TODO: don't repeat tenses + let v: T.VPSelectionState; + do { + v = getRandomVPSelection("tenses")(vps); + // eslint-disable-next-line + } while (wrongStates.find(x => x.verb.tense === v.verb.tense)); + wrongStates.push(v); + }); + const answer = makeRes(vps); + const wrongAnswers = wrongStates.map(makeRes); + const allAnswers = shuffleArray([...wrongAnswers, answer]); + const options = allAnswers.map(getOptionFromResult); + return { + VPS: vps, + qs: { + answer, + options, + result: "waiting", + }, + }; +} + +function isInAnswer(a: T.PsString, answer: { + ps: T.SingleOrLengthOpts; + e?: string[] | undefined; +}): boolean { + if ("long" in answer.ps) { + return isInAnswer(a, { ...answer, ps: answer.ps.long }) || + isInAnswer(a, { ...answer, ps: answer.ps.short }) || + !!(answer.ps.mini && isInAnswer(a, { ...answer, ps: answer.ps.mini })); + } + return answer.ps.some((x) => psStringEquals(x, a)); +} + +function getOptionFromResult(r: { + ps: T.SingleOrLengthOpts; + e?: string[] | undefined; +}): T.PsString { + // TODO: randomize length pick + const ps = "long" in r.ps ? r.ps.long : r.ps; + // TODO: randomize version pick + return ps[0]; +} + +function getRandomVPSelection(mix: MixType = "both") { + // TODO: Type safety to make sure it's safe? return ({ subject, verb }: T.VPSelectionState): T.VPSelectionState => { if (mix === "tenses") { return { diff --git a/src/lib/shuffle-array.ts b/src/lib/shuffle-array.ts new file mode 100644 index 0000000..9d19bcf --- /dev/null +++ b/src/lib/shuffle-array.ts @@ -0,0 +1,24 @@ +// https://stackoverflow.com/a/2450976 + +function shuffleArray(arr: Readonly>): Array { + let currentIndex = arr.length, temporaryValue, randomIndex; + + const array = [...arr]; + + // While there remain elements to shuffle... + while (0 !== currentIndex) { + + // Pick a remaining element... + randomIndex = Math.floor(Math.random() * currentIndex); + currentIndex -= 1; + + // And swap it with the current element. + temporaryValue = array[currentIndex]; + array[currentIndex] = array[randomIndex]; + array[randomIndex] = temporaryValue; + } + + return array; +} + +export default shuffleArray; \ No newline at end of file diff --git a/src/library.ts b/src/library.ts index 219bd46..d35decd 100644 --- a/src/library.ts +++ b/src/library.ts @@ -111,6 +111,7 @@ import { splitUpSyllables, countSyllables, } from "./lib/accent-helpers"; +import shuffleArray from "./lib/shuffle-array"; import defaultTextOptions from "./lib/default-text-options"; import * as grammarUnits from "./lib/grammar-units"; import genderColors from "./lib/gender-colors"; @@ -167,6 +168,7 @@ export { randomPerson, isInvalidSubjObjCombo, randomSubjObj, + shuffleArray, // protobuf helpers readDictionary, writeDictionary, diff --git a/yarn.lock b/yarn.lock index b7f182c..e8a918e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9523,6 +9523,11 @@ react-refresh@^0.8.3: resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" integrity sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg== +react-rewards@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/react-rewards/-/react-rewards-2.0.3.tgz#685aee98654ab4f060e297849f39cf0a16cec042" + integrity sha512-qww5Jtk2HmCjR9wc7+0c2iP8oCQzENZn8pnoJGi0S6o+6dAD25+ZoagLSWdoBLGVwxfP5kFBjv3VZ6L8fPk6lg== + react-scripts@4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/react-scripts/-/react-scripts-4.0.3.tgz#b1cafed7c3fa603e7628ba0f187787964cb5d345"