a bit of refactoring

This commit is contained in:
lingdocs 2022-04-13 13:08:44 +05:00
parent 6c53b2a896
commit 68633089f9
7 changed files with 78 additions and 84 deletions

View File

@ -69,8 +69,8 @@ export function getRandomTense(type: "basic" | "modal" | "perfect", o?: T.Perfec
} }
function TensePicker({ onChange, vps, mode, locked }: { function TensePicker({ onChange, vps, mode, locked }: {
vps: T.VPSelectionState, vps: T.VPSelection,
onChange: (p: T.VPSelectionState) => void, onChange: (p: T.VPSelection) => void,
mode: "charts" | "phrases" | "quiz", mode: "charts" | "phrases" | "quiz",
locked: boolean, locked: boolean,
}) { }) {

View File

@ -18,6 +18,9 @@ import InlinePs from "../InlinePs";
import { psStringEquals } from "../../lib/p-text-helpers"; import { psStringEquals } from "../../lib/p-text-helpers";
import { randFromArray } from "../../lib/misc-helpers"; import { randFromArray } from "../../lib/misc-helpers";
import playAudio from "../../lib/play-audio"; 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'; // import { useReward } from 'react-rewards';
const kingEmoji = "👑"; const kingEmoji = "👑";
@ -35,6 +38,9 @@ const answerFeedback: CSSProperties = {
"transform": "translate(-50%, -50%)", "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: Drill Down text display options
// TODO: SHOW KING AND SERVANT ONCE TENSE PICKED, EVEN IF NPs not selected // 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, getNounByTs: (ts: number) => T.NounEntry | undefined,
getVerbByTs: (ts: number) => T.VerbEntry | undefined, getVerbByTs: (ts: number) => T.VerbEntry | undefined,
})) { })) {
const [vps, setVps] = useStickyState<T.VPSelectionState>( const [vps, setVps] = useStickyState<T.VPSelection>(
o => makeVPSelectionState(props.verb, o), savedVps => makeVPSelectionState(props.verb, savedVps),
"vpsState1", "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<QuizState | undefined>(undefined); const [quizState, setQuizState] = useState<QuizState | undefined>(undefined);
const [showCheck, setShowCheck] = useState<boolean>(false); const [showCheck, setShowCheck] = useState<boolean>(false);
const [currentCorrectEmoji, setCurrentCorrectEmoji] = useState<string>(randFromArray(correctEmoji)); const [currentCorrectEmoji, setCurrentCorrectEmoji] = useState<string>(randFromArray(correctEmoji));
// const { reward } = useReward('rewardId', "emoji", {
// emoji: ['🤓', '😊', '🥳', "👏", "💯", "😎", "👍"],
// lifetime: 50,
// elementCount: 10,
// elementSize: 30,
// });
useEffect(() => {
if (mode === "quiz") {
handleResetQuiz();
}
// eslint-disable-next-line
}, []);
useEffect(() => { useEffect(() => {
setVps(o => { setVps(o => {
if (mode === "quiz") { if (mode === "quiz") {
const newvps = makeVPSelectionState(props.verb, o); setMode("phrases");
const { VPS, qs } = makeQuizState(newvps);
setQuizState(qs);
return VPS;
} }
return makeVPSelectionState(props.verb, o); return makeVPSelectionState(props.verb, o);
}); });
@ -148,7 +146,10 @@ export function VPExplorer(props: {
} }
function quizLock<T>(f: T) { function quizLock<T>(f: T) {
if (mode === "quiz") { if (mode === "quiz") {
return () => null; return () => {
alert("to adjust this, get out of quiz mode");
return null;
};
} }
return f; return f;
} }
@ -177,8 +178,6 @@ export function VPExplorer(props: {
}); });
} }
} }
const verbPhrase: T.VPSelectionComplete | undefined = completeVPSelection(vps);
const VPRendered = verbPhrase && renderVP(verbPhrase);
return <div className="mt-3" style={{ maxWidth: "950px"}}> return <div className="mt-3" style={{ maxWidth: "950px"}}>
<VerbPicker <VerbPicker
{..."getNounByTs" in props ? { {..."getNounByTs" in props ? {
@ -188,7 +187,7 @@ export function VPExplorer(props: {
verbs: props.verbs, verbs: props.verbs,
}} }}
vps={vps} vps={vps}
onChange={setVps} onChange={quizLock(setVps)}
opts={props.opts} opts={props.opts}
/> />
<div className="mt-2 mb-3 text-center"> <div className="mt-2 mb-3 text-center">
@ -211,7 +210,7 @@ export function VPExplorer(props: {
<div className="d-flex flex-row justify-content-around flex-wrap" style={{ marginLeft: "-0.5rem", marginRight: "-0.5rem" }}> <div className="d-flex flex-row justify-content-around flex-wrap" style={{ marginLeft: "-0.5rem", marginRight: "-0.5rem" }}>
{mode !== "charts" && <> {mode !== "charts" && <>
<div className="my-2"> <div className="my-2">
<div className="h5 text-center">Subject {showRole(VPRendered, "subject")}</div> <div className="h5 text-center">Subject {showRole(vps, "subject")}</div>
<NPPicker <NPPicker
{..."getNounByTs" in props ? { {..."getNounByTs" in props ? {
getNounByTs: props.getNounByTs, getNounByTs: props.getNounByTs,
@ -230,7 +229,7 @@ export function VPExplorer(props: {
/> />
</div> </div>
{vps.verb && (vps.verb.object !== "none") && <div className="my-2"> {vps.verb && (vps.verb.object !== "none") && <div className="my-2">
<div className="h5 text-center">Object {showRole(VPRendered, "object")}</div> <div className="h5 text-center">Object {showRole(vps, "object")}</div>
{(typeof vps.verb.object === "number") {(typeof vps.verb.object === "number")
? <div className="text-muted">Unspoken 3rd Pers. Masc. Plur.</div> ? <div className="text-muted">Unspoken 3rd Pers. Masc. Plur.</div>
: <NPPicker : <NPPicker
@ -261,8 +260,8 @@ export function VPExplorer(props: {
/> />
</div> </div>
</div> </div>
{(verbPhrase && (mode === "phrases")) && {(isVPSelectionComplete(vps) && (mode === "phrases")) &&
<VPDisplay VP={verbPhrase} opts={props.opts} /> <VPDisplay VP={vps} opts={props.opts} />
} }
{(vps.verb && (mode === "charts")) && <ChartDisplay VS={vps.verb} opts={props.opts} />} {(vps.verb && (mode === "charts")) && <ChartDisplay VS={vps.verb} opts={props.opts} />}
{(mode === "quiz" && quizState) && <div className="text-center"> {(mode === "quiz" && quizState) && <div className="text-center">
@ -296,18 +295,6 @@ export function VPExplorer(props: {
export default VPExplorer; 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 { function hasPronounConflict(subject: T.NPSelection | undefined, object: undefined | T.VerbObject): boolean {
const subjPronoun = (subject && subject.type === "pronoun") ? subject : undefined; const subjPronoun = (subject && subject.type === "pronoun") ? subject : undefined;
const objPronoun = (object && typeof object === "object" && object.type === "pronoun") ? object : 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); 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 return VP
? <span className="ml-2"> ? <span className="ml-2">
{(VP.king === member ? kingEmoji : VP.servant === member ? servantEmoji : "")} {(roles.king === member ? kingEmoji : roles.servant === member ? servantEmoji : "")}
</span> </span>
: ""; : "";
} }
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")) { if (!subject|| !verb || !verb.object || !(typeof verb.object === "object")) {
return { subject, verb }; 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 makeQuizState(oldVps: T.VPSelection): { VPS: T.VPSelectionComplete, qs: QuizState } {
function makeRes(x: T.VPSelectionState) { function makeRes(x: T.VPSelectionComplete) {
const y = completeVPSelection(x); return compileVP(renderVP(x), { removeKing: false, shrinkServant: false });
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 vps = getRandomVPSelection("both")(oldVps);
const wrongStates: T.VPSelectionState[] = []; const wrongStates: T.VPSelectionComplete[] = [];
// don't do the SO switches every time // don't do the SO switches every time
const wholeTimeSOSwitch = randFromArray([true, false]); const wholeTimeSOSwitch = randFromArray([true, false]);
[1, 2, 3].forEach(() => { [1, 2, 3].forEach(() => {
let v: T.VPSelectionState; let v: T.VPSelectionComplete;
do { do {
const SOSwitch = wholeTimeSOSwitch && randFromArray([true, false]); const SOSwitch = wholeTimeSOSwitch && randFromArray([true, false]);
// TODO: if switich subj and obj, include the tense being correct maybe // TODO: if switich subj and obj, include the tense being correct maybe
@ -399,13 +386,7 @@ function getOptionFromResult(r: {
function getRandomVPSelection(mix: MixType = "both") { function getRandomVPSelection(mix: MixType = "both") {
// TODO: Type safety to make sure it's safe? // TODO: Type safety to make sure it's safe?
return ({ subject, verb }: T.VPSelectionState): T.VPSelectionState => { return ({ subject, verb }: T.VPSelection): T.VPSelectionComplete => {
if (mix === "tenses") {
return {
subject,
verb: randomizeTense(verb, true),
}
}
const oldSubj = (subject?.type === "pronoun") const oldSubj = (subject?.type === "pronoun")
? subject.person ? subject.person
: undefined; : undefined;
@ -432,7 +413,8 @@ function getRandomVPSelection(mix: MixType = "both") {
person: obj, person: obj,
}; };
const s = randSubj; const s = randSubj;
const v: T.VerbSelection = { // ensure that the verb selection is complete
const v: T.VerbSelectionComplete = {
...verb, ...verb,
object: ( object: (
(typeof verb.object === "object" && !(verb.object.type === "noun" && verb.object.dynamicComplement)) (typeof verb.object === "object" && !(verb.object.type === "noun" && verb.object.dynamicComplement))
@ -442,6 +424,12 @@ function getRandomVPSelection(mix: MixType = "both") {
? randObj ? randObj
: verb.object, : verb.object,
}; };
if (mix === "tenses") {
return {
subject: subject !== undefined ? subject : randSubj,
verb: randomizeTense(v, true),
}
}
return { return {
subject: s, subject: s,
verb: randomizeTense(v, true), 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 { return {
...verb, ...verb,
tense: getRandomTense( tense: getRandomTense(

View File

@ -9,8 +9,8 @@ import useStickyState from "../../lib/useStickyState";
// TODO: dark on past tense selecitons // TODO: dark on past tense selecitons
function VerbPicker(props: { function VerbPicker(props: {
vps: T.VPSelectionState, vps: T.VPSelection,
onChange: (p: T.VPSelectionState) => void, onChange: (p: T.VPSelection) => void,
opts: T.TextOptions, opts: T.TextOptions,
}) { }) {
const [showRootsAndStems, setShowRootsAndStems] = useStickyState<boolean>(false, "showRootsAndStems"); const [showRootsAndStems, setShowRootsAndStems] = useStickyState<boolean>(false, "showRootsAndStems");
@ -31,20 +31,15 @@ function VerbPicker(props: {
props.onChange({ props.onChange({
...props.vps, ...props.vps,
subject: props.vps.verb.object, subject: props.vps.verb.object,
})
}
if (value === "active") {
props.onChange({
...props.vps,
subject: undefined,
}); });
} } else {
props.onChange({ props.onChange({
...props.vps, ...props.vps,
verb: props.vps.verb.changeVoice(value, value === "active" ? props.vps.subject : undefined), verb: props.vps.verb.changeVoice(value, value === "active" ? props.vps.subject : undefined),
}); });
} }
} }
}
function notInstransitive(t: "transitive" | "intransitive" | "grammatically transitive"): "transitive" | "grammatically transitive" { function notInstransitive(t: "transitive" | "intransitive" | "grammatically transitive"): "transitive" | "grammatically transitive" {
return t === "intransitive" ? "transitive" : t; return t === "intransitive" ? "transitive" : t;
} }

View File

@ -7,8 +7,8 @@ import { isPerfectTense } from "../../lib/phrase-building/vp-tools";
export function makeVPSelectionState( export function makeVPSelectionState(
verb: T.VerbEntry, verb: T.VerbEntry,
os?: T.VPSelectionState, os?: T.VPSelection,
): T.VPSelectionState { ): T.VPSelection {
const info = getVerbInfo(verb.entry, verb.complement); const info = getVerbInfo(verb.entry, verb.complement);
const subject = (os?.verb.voice === "passive" && info.type === "dynamic compound") const subject = (os?.verb.voice === "passive" && info.type === "dynamic compound")
? makeNounSelection(info.objComplement.entry as T.NounEntry, true) ? makeNounSelection(info.objComplement.entry as T.NounEntry, true)

View File

@ -30,18 +30,20 @@ import { renderEnglishVPBase } from "./english-vp-rendering";
export function renderVP(VP: T.VPSelectionComplete): T.VPRendered { export function renderVP(VP: T.VPSelectionComplete): T.VPRendered {
// Sentence Rules Logic // Sentence Rules Logic
const isPast = isPastTense(VP.verb.tense); const isPast = isPastTense(VP.verb.tense);
const isTransitive = VP.object !== "none"; const isTransitive = VP.verb.object !== "none";
const { king, servant } = getKingAndServant(isPast, isTransitive); 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 // TODO: more elegant way of handling this type safety
if (kingPerson === undefined) { if (kingPerson === undefined) {
throw new Error("king of sentance does not exist"); throw new Error("king of sentance does not exist");
} }
const subjectPerson = getPersonFromNP(VP.subject); 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 // TODO: also don't inflect if it's a pattern one animate noun
const inflectSubject = isPast && isTransitive && !isMascSingAnimatePattern4(VP.subject); const inflectSubject = isPast && isTransitive && !isMascSingAnimatePattern4(VP.subject);
const inflectObject = !isPast && isFirstOrSecondPersPronoun(VP.object); const inflectObject = !isPast && isFirstOrSecondPersPronoun(VP.verb.object);
// Render Elements // Render Elements
return { return {
type: "VPRendered", type: "VPRendered",
@ -51,11 +53,11 @@ export function renderVP(VP: T.VPSelectionComplete): T.VPRendered {
isTransitive, isTransitive,
isCompound: VP.verb.isCompound, isCompound: VP.verb.isCompound,
subject: renderNPSelection(VP.subject, inflectSubject, false, "subject"), 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), verb: renderVerbSelection(VP.verb, kingPerson, objectPerson),
englishBase: renderEnglishVPBase({ englishBase: renderEnglishVPBase({
subjectPerson, subjectPerson,
object: VP.verb.isCompound === "dynamic" ? "none" : VP.object, object: VP.verb.isCompound === "dynamic" ? "none" : VP.verb.object,
vs: VP.verb, vs: VP.verb,
}), }),
}; };
@ -300,7 +302,7 @@ function getInf(infs: T.InflectorOutput, t: "plural" | "arabicPlural" | "inflect
return []; return [];
} }
function getKingAndServant(isPast: boolean, isTransitive: boolean): export function getKingAndServant(isPast: boolean, isTransitive: boolean):
{ king: "subject", servant: "object" } | { king: "subject", servant: "object" } |
{ king: "object", servant: "subject" } | { king: "object", servant: "subject" } |
{ king: "subject", servant: undefined } { { king: "subject", servant: undefined } {

View File

@ -159,3 +159,10 @@ export function isSingularEntry<U extends T.NounEntry>(e: U): e is T.SingularEnt
export function isArrayOneOrMore<U>(a: U[]): a is T.ArrayOneOrMore<U> { export function isArrayOneOrMore<U>(a: U[]): a is T.ArrayOneOrMore<U> {
return a.length > 0; 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;
}

View File

@ -536,16 +536,18 @@ export type NounNumber = "singular" | "plural";
export type PerfectTense = `${EquativeTense} perfect`; export type PerfectTense = `${EquativeTense} perfect`;
export type VPSelectionState = { export type VPSelection = {
subject: NPSelection | undefined, subject: NPSelection | undefined,
verb: VerbSelection, verb: VerbSelection,
}; };
export type VPSelectionComplete = { export type VPSelectionComplete = {
type: "VPSelectionComplete",
subject: NPSelection, subject: NPSelection,
verb: VerbSelectionComplete,
};
export type VerbSelectionComplete = Exclude<VerbSelection, "object"> & {
object: Exclude<VerbObject, undefined>, object: Exclude<VerbObject, undefined>,
verb: Exclude<VerbSelection, "object">,
}; };
export type VerbSelection = { export type VerbSelection = {