a bit of refactoring
This commit is contained in:
parent
6c53b2a896
commit
68633089f9
|
@ -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,
|
||||
}) {
|
||||
|
|
|
@ -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<T.VPSelectionState>(
|
||||
o => makeVPSelectionState(props.verb, o),
|
||||
const [vps, setVps] = useStickyState<T.VPSelection>(
|
||||
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<QuizState | undefined>(undefined);
|
||||
const [showCheck, setShowCheck] = useState<boolean>(false);
|
||||
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(() => {
|
||||
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<T>(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 <div className="mt-3" style={{ maxWidth: "950px"}}>
|
||||
<VerbPicker
|
||||
{..."getNounByTs" in props ? {
|
||||
|
@ -188,7 +187,7 @@ export function VPExplorer(props: {
|
|||
verbs: props.verbs,
|
||||
}}
|
||||
vps={vps}
|
||||
onChange={setVps}
|
||||
onChange={quizLock(setVps)}
|
||||
opts={props.opts}
|
||||
/>
|
||||
<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" }}>
|
||||
{mode !== "charts" && <>
|
||||
<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
|
||||
{..."getNounByTs" in props ? {
|
||||
getNounByTs: props.getNounByTs,
|
||||
|
@ -230,7 +229,7 @@ export function VPExplorer(props: {
|
|||
/>
|
||||
</div>
|
||||
{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")
|
||||
? <div className="text-muted">Unspoken 3rd Pers. Masc. Plur.</div>
|
||||
: <NPPicker
|
||||
|
@ -261,8 +260,8 @@ export function VPExplorer(props: {
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
{(verbPhrase && (mode === "phrases")) &&
|
||||
<VPDisplay VP={verbPhrase} opts={props.opts} />
|
||||
{(isVPSelectionComplete(vps) && (mode === "phrases")) &&
|
||||
<VPDisplay VP={vps} opts={props.opts} />
|
||||
}
|
||||
{(vps.verb && (mode === "charts")) && <ChartDisplay VS={vps.verb} opts={props.opts} />}
|
||||
{(mode === "quiz" && quizState) && <div className="text-center">
|
||||
|
@ -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
|
||||
? <span className="ml-2">
|
||||
{(VP.king === member ? kingEmoji : VP.servant === member ? servantEmoji : "")}
|
||||
{(roles.king === member ? kingEmoji : roles.servant === member ? servantEmoji : "")}
|
||||
</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")) {
|
||||
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(
|
||||
|
|
|
@ -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<boolean>(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" {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 } {
|
||||
|
|
|
@ -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> {
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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<VerbSelection, "object"> & {
|
||||
object: Exclude<VerbObject, undefined>,
|
||||
verb: Exclude<VerbSelection, "object">,
|
||||
};
|
||||
|
||||
export type VerbSelection = {
|
||||
|
|
Loading…
Reference in New Issue