From 68633089f9fa8c712b4b1c7fb90ab2d67df5b8cb Mon Sep 17 00:00:00 2001 From: lingdocs <71590811+lingdocs@users.noreply.github.com> Date: Wed, 13 Apr 2022 13:08:44 +0500 Subject: [PATCH] a bit of refactoring --- src/components/vp-explorer/TensePicker.tsx | 4 +- src/components/vp-explorer/VPExplorer.tsx | 108 +++++++++---------- src/components/vp-explorer/VerbPicker.tsx | 15 +-- src/components/vp-explorer/verb-selection.ts | 4 +- src/lib/phrase-building/render-vp.ts | 16 +-- src/lib/type-predicates.ts | 7 ++ src/types.ts | 8 +- 7 files changed, 78 insertions(+), 84 deletions(-) diff --git a/src/components/vp-explorer/TensePicker.tsx b/src/components/vp-explorer/TensePicker.tsx index fa11cc6..59513b2 100644 --- a/src/components/vp-explorer/TensePicker.tsx +++ b/src/components/vp-explorer/TensePicker.tsx @@ -69,8 +69,8 @@ export function getRandomTense(type: "basic" | "modal" | "perfect", o?: T.Perfec } function TensePicker({ onChange, vps, mode, locked }: { - vps: T.VPSelectionState, - onChange: (p: T.VPSelectionState) => void, + vps: T.VPSelection, + onChange: (p: T.VPSelection) => void, mode: "charts" | "phrases" | "quiz", locked: boolean, }) { diff --git a/src/components/vp-explorer/VPExplorer.tsx b/src/components/vp-explorer/VPExplorer.tsx index f266b79..08ae8f8 100644 --- a/src/components/vp-explorer/VPExplorer.tsx +++ b/src/components/vp-explorer/VPExplorer.tsx @@ -18,6 +18,9 @@ import InlinePs from "../InlinePs"; import { psStringEquals } from "../../lib/p-text-helpers"; import { randFromArray } from "../../lib/misc-helpers"; import playAudio from "../../lib/play-audio"; +import { isVPSelectionComplete } from "../../lib/type-predicates"; +import { getKingAndServant } from "../../lib/phrase-building/render-vp"; +import { isPastTense } from "../../lib/phrase-building/vp-tools"; // import { useReward } from 'react-rewards'; const kingEmoji = "👑"; @@ -35,6 +38,9 @@ const answerFeedback: CSSProperties = { "transform": "translate(-50%, -50%)", } +// TODO: make answerFeedback emojis appear at random translate angles a little bit +// add energy drinks? + // TODO: Drill Down text display options // TODO: SHOW KING AND SERVANT ONCE TENSE PICKED, EVEN IF NPs not selected @@ -72,33 +78,25 @@ export function VPExplorer(props: { getNounByTs: (ts: number) => T.NounEntry | undefined, getVerbByTs: (ts: number) => T.VerbEntry | undefined, })) { - const [vps, setVps] = useStickyState( - o => makeVPSelectionState(props.verb, o), + const [vps, setVps] = useStickyState( + savedVps => makeVPSelectionState(props.verb, savedVps), "vpsState1", ); - const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">("phrases", "verbExplorerMode"); + const [mode, setMode] = useStickyState<"charts" | "phrases" | "quiz">( + savedMode => { + if (!savedMode) return "charts"; + if (savedMode === "quiz") return "phrases"; + return savedMode; + }, + "verbExplorerMode", + ); const [quizState, setQuizState] = useState(undefined); const [showCheck, setShowCheck] = useState(false); const [currentCorrectEmoji, setCurrentCorrectEmoji] = useState(randFromArray(correctEmoji)); - // const { reward } = useReward('rewardId', "emoji", { - // emoji: ['🤓', '😊', '🥳', "👏", "💯", "😎", "👍"], - // lifetime: 50, - // elementCount: 10, - // elementSize: 30, - // }); - useEffect(() => { - if (mode === "quiz") { - handleResetQuiz(); - } - // eslint-disable-next-line - }, []); useEffect(() => { setVps(o => { if (mode === "quiz") { - const newvps = makeVPSelectionState(props.verb, o); - const { VPS, qs } = makeQuizState(newvps); - setQuizState(qs); - return VPS; + setMode("phrases"); } return makeVPSelectionState(props.verb, o); }); @@ -148,7 +146,10 @@ export function VPExplorer(props: { } function quizLock(f: T) { if (mode === "quiz") { - return () => null; + return () => { + alert("to adjust this, get out of quiz mode"); + return null; + }; } return f; } @@ -177,8 +178,6 @@ export function VPExplorer(props: { }); } } - const verbPhrase: T.VPSelectionComplete | undefined = completeVPSelection(vps); - const VPRendered = verbPhrase && renderVP(verbPhrase); return
@@ -211,7 +210,7 @@ export function VPExplorer(props: {
{mode !== "charts" && <>
-
Subject {showRole(VPRendered, "subject")}
+
Subject {showRole(vps, "subject")}
{vps.verb && (vps.verb.object !== "none") &&
-
Object {showRole(VPRendered, "object")}
+
Object {showRole(vps, "object")}
{(typeof vps.verb.object === "number") ?
Unspoken 3rd Pers. Masc. Plur.
:
- {(verbPhrase && (mode === "phrases")) && - + {(isVPSelectionComplete(vps) && (mode === "phrases")) && + } {(vps.verb && (mode === "charts")) && } {(mode === "quiz" && quizState) &&
@@ -296,18 +295,6 @@ export function VPExplorer(props: { export default VPExplorer; -function completeVPSelection(vps: T.VPSelectionState): T.VPSelectionComplete | undefined { - if (vps.subject === undefined) return undefined - if (vps.verb.object === undefined) return undefined; - const verb = vps.verb; - return { - type: "VPSelectionComplete", - subject: vps.subject, - object: vps.verb.object, - verb, - } -} - function hasPronounConflict(subject: T.NPSelection | undefined, object: undefined | T.VerbObject): boolean { const subjPronoun = (subject && subject.type === "pronoun") ? subject : undefined; const objPronoun = (object && typeof object === "object" && object.type === "pronoun") ? object : undefined; @@ -315,15 +302,19 @@ function hasPronounConflict(subject: T.NPSelection | undefined, object: undefine return isInvalidSubjObjCombo(subjPronoun.person, objPronoun.person); } -function showRole(VP: T.VPRendered | undefined, member: "subject" | "object") { +function showRole(VP: T.VPSelection, member: "subject" | "object") { + const roles = getKingAndServant( + isPastTense(VP.verb.tense), + VP.verb.transitivity !== "intransitive", + ); return VP ? - {(VP.king === member ? kingEmoji : VP.servant === member ? servantEmoji : "")} + {(roles.king === member ? kingEmoji : roles.servant === member ? servantEmoji : "")} : ""; } -function switchSubjObj({ subject, verb }: T.VPSelectionState): T.VPSelectionState { +function switchSubjObj({ subject, verb }: T.VPSelection): T.VPSelection { if (!subject|| !verb || !verb.object || !(typeof verb.object === "object")) { return { subject, verb }; } @@ -336,20 +327,16 @@ function switchSubjObj({ subject, verb }: T.VPSelectionState): T.VPSelectionStat }; } -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 }); +function makeQuizState(oldVps: T.VPSelection): { VPS: T.VPSelectionComplete, qs: QuizState } { + function makeRes(x: T.VPSelectionComplete) { + return compileVP(renderVP(x), { removeKing: false, shrinkServant: false }); } const vps = getRandomVPSelection("both")(oldVps); - const wrongStates: T.VPSelectionState[] = []; + const wrongStates: T.VPSelectionComplete[] = []; // don't do the SO switches every time const wholeTimeSOSwitch = randFromArray([true, false]); [1, 2, 3].forEach(() => { - let v: T.VPSelectionState; + let v: T.VPSelectionComplete; do { const SOSwitch = wholeTimeSOSwitch && randFromArray([true, false]); // TODO: if switich subj and obj, include the tense being correct maybe @@ -399,13 +386,7 @@ function getOptionFromResult(r: { 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 { - subject, - verb: randomizeTense(verb, true), - } - } + return ({ subject, verb }: T.VPSelection): T.VPSelectionComplete => { const oldSubj = (subject?.type === "pronoun") ? subject.person : undefined; @@ -432,7 +413,8 @@ function getRandomVPSelection(mix: MixType = "both") { person: obj, }; const s = randSubj; - const v: T.VerbSelection = { + // ensure that the verb selection is complete + const v: T.VerbSelectionComplete = { ...verb, object: ( (typeof verb.object === "object" && !(verb.object.type === "noun" && verb.object.dynamicComplement)) @@ -442,6 +424,12 @@ function getRandomVPSelection(mix: MixType = "both") { ? randObj : verb.object, }; + if (mix === "tenses") { + return { + subject: subject !== undefined ? subject : randSubj, + verb: randomizeTense(v, true), + } + } return { subject: s, verb: randomizeTense(v, true), @@ -449,7 +437,7 @@ function getRandomVPSelection(mix: MixType = "both") { }; }; -function randomizeTense(verb: T.VerbSelection, dontRepeatTense: boolean): T.VerbSelection { +function randomizeTense(verb: T.VerbSelectionComplete, dontRepeatTense: boolean): T.VerbSelectionComplete { return { ...verb, tense: getRandomTense( diff --git a/src/components/vp-explorer/VerbPicker.tsx b/src/components/vp-explorer/VerbPicker.tsx index cb4316d..019eea8 100644 --- a/src/components/vp-explorer/VerbPicker.tsx +++ b/src/components/vp-explorer/VerbPicker.tsx @@ -9,8 +9,8 @@ import useStickyState from "../../lib/useStickyState"; // TODO: dark on past tense selecitons function VerbPicker(props: { - vps: T.VPSelectionState, - onChange: (p: T.VPSelectionState) => void, + vps: T.VPSelection, + onChange: (p: T.VPSelection) => void, opts: T.TextOptions, }) { const [showRootsAndStems, setShowRootsAndStems] = useStickyState(false, "showRootsAndStems"); @@ -31,18 +31,13 @@ function VerbPicker(props: { props.onChange({ ...props.vps, subject: props.vps.verb.object, - }) - } - if (value === "active") { + }); + } else { props.onChange({ ...props.vps, - subject: undefined, + verb: props.vps.verb.changeVoice(value, value === "active" ? props.vps.subject : undefined), }); } - props.onChange({ - ...props.vps, - verb: props.vps.verb.changeVoice(value, value === "active" ? props.vps.subject : undefined), - }); } } function notInstransitive(t: "transitive" | "intransitive" | "grammatically transitive"): "transitive" | "grammatically transitive" { diff --git a/src/components/vp-explorer/verb-selection.ts b/src/components/vp-explorer/verb-selection.ts index 5829c67..89e2028 100644 --- a/src/components/vp-explorer/verb-selection.ts +++ b/src/components/vp-explorer/verb-selection.ts @@ -7,8 +7,8 @@ import { isPerfectTense } from "../../lib/phrase-building/vp-tools"; export function makeVPSelectionState( verb: T.VerbEntry, - os?: T.VPSelectionState, -): T.VPSelectionState { + os?: T.VPSelection, +): T.VPSelection { const info = getVerbInfo(verb.entry, verb.complement); const subject = (os?.verb.voice === "passive" && info.type === "dynamic compound") ? makeNounSelection(info.objComplement.entry as T.NounEntry, true) diff --git a/src/lib/phrase-building/render-vp.ts b/src/lib/phrase-building/render-vp.ts index 454ab3e..ad91477 100644 --- a/src/lib/phrase-building/render-vp.ts +++ b/src/lib/phrase-building/render-vp.ts @@ -30,18 +30,20 @@ import { renderEnglishVPBase } from "./english-vp-rendering"; export function renderVP(VP: T.VPSelectionComplete): T.VPRendered { // Sentence Rules Logic const isPast = isPastTense(VP.verb.tense); - const isTransitive = VP.object !== "none"; + const isTransitive = VP.verb.object !== "none"; const { king, servant } = getKingAndServant(isPast, isTransitive); - const kingPerson = getPersonFromNP(VP[king]); + const kingPerson = getPersonFromNP( + king === "subject" ? VP.subject : VP.verb.object, + ); // TODO: more elegant way of handling this type safety if (kingPerson === undefined) { throw new Error("king of sentance does not exist"); } const subjectPerson = getPersonFromNP(VP.subject); - const objectPerson = getPersonFromNP(VP.object); + const objectPerson = getPersonFromNP(VP.verb.object); // TODO: also don't inflect if it's a pattern one animate noun const inflectSubject = isPast && isTransitive && !isMascSingAnimatePattern4(VP.subject); - const inflectObject = !isPast && isFirstOrSecondPersPronoun(VP.object); + const inflectObject = !isPast && isFirstOrSecondPersPronoun(VP.verb.object); // Render Elements return { type: "VPRendered", @@ -51,11 +53,11 @@ export function renderVP(VP: T.VPSelectionComplete): T.VPRendered { isTransitive, isCompound: VP.verb.isCompound, subject: renderNPSelection(VP.subject, inflectSubject, false, "subject"), - object: renderNPSelection(VP.object, inflectObject, true, "object"), + object: renderNPSelection(VP.verb.object, inflectObject, true, "object"), verb: renderVerbSelection(VP.verb, kingPerson, objectPerson), englishBase: renderEnglishVPBase({ subjectPerson, - object: VP.verb.isCompound === "dynamic" ? "none" : VP.object, + object: VP.verb.isCompound === "dynamic" ? "none" : VP.verb.object, vs: VP.verb, }), }; @@ -300,7 +302,7 @@ function getInf(infs: T.InflectorOutput, t: "plural" | "arabicPlural" | "inflect return []; } -function getKingAndServant(isPast: boolean, isTransitive: boolean): +export function getKingAndServant(isPast: boolean, isTransitive: boolean): { king: "subject", servant: "object" } | { king: "object", servant: "subject" } | { king: "subject", servant: undefined } { diff --git a/src/lib/type-predicates.ts b/src/lib/type-predicates.ts index 5b9e69a..c745c3c 100644 --- a/src/lib/type-predicates.ts +++ b/src/lib/type-predicates.ts @@ -159,3 +159,10 @@ export function isSingularEntry(e: U): e is T.SingularEnt export function isArrayOneOrMore(a: U[]): a is T.ArrayOneOrMore { return a.length > 0; } + +export function isVPSelectionComplete(vps: T.VPSelection | T.VPSelectionComplete): vps is T.VPSelectionComplete { + if ((vps.subject !== undefined) && (vps.verb.object !== undefined)) { + return true; + } + return false; +} diff --git a/src/types.ts b/src/types.ts index 2f500b5..5193a5f 100644 --- a/src/types.ts +++ b/src/types.ts @@ -536,16 +536,18 @@ export type NounNumber = "singular" | "plural"; export type PerfectTense = `${EquativeTense} perfect`; -export type VPSelectionState = { +export type VPSelection = { subject: NPSelection | undefined, verb: VerbSelection, }; export type VPSelectionComplete = { - type: "VPSelectionComplete", subject: NPSelection, + verb: VerbSelectionComplete, +}; + +export type VerbSelectionComplete = Exclude & { object: Exclude, - verb: Exclude, }; export type VerbSelection = {