EP adjective game
This commit is contained in:
parent
1550409440
commit
dd2a69985b
|
@ -7,7 +7,7 @@
|
|||
"@formkit/auto-animate": "^1.0.0-beta.1",
|
||||
"@fortawesome/fontawesome-free": "^5.15.4",
|
||||
"@lingdocs/lingdocs-main": "^0.3.3",
|
||||
"@lingdocs/ps-react": "^5.3.1",
|
||||
"@lingdocs/ps-react": "^5.3.3",
|
||||
"@testing-library/jest-dom": "^5.11.4",
|
||||
"@testing-library/react": "^11.1.0",
|
||||
"@testing-library/user-event": "^12.1.10",
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
import {
|
||||
Types as T,
|
||||
Examples,
|
||||
defaultTextOptions as opts,
|
||||
firstVariation,
|
||||
removeFVarients,
|
||||
getInflectionPattern,
|
||||
HumanReadableInflectionPattern,
|
||||
} from "@lingdocs/ps-react";
|
||||
|
||||
function WordCard({ showHint, entry, selection }: {
|
||||
showHint: boolean
|
||||
} & ({
|
||||
entry: T.AdjectiveEntry,
|
||||
selection: undefined,
|
||||
} | {
|
||||
entry: T.NounEntry,
|
||||
selection: T.NounSelection,
|
||||
})) {
|
||||
const e = removeFVarients(entry);
|
||||
return <div className="card" style={{ minWidth: "10rem", maxWidth: "15rem" }}>
|
||||
<div className="card-body" style={{ padding: "0.25rem" }}>
|
||||
<Examples opts={opts}>{[
|
||||
{
|
||||
p: e.p,
|
||||
f: e.f,
|
||||
e: `${firstVariation(e.e)} - ${e.c}`,
|
||||
}
|
||||
]}</Examples>
|
||||
{selection && <div style={{ marginTop: "-0.75rem"}}>
|
||||
{selection.genderCanChange && selection.gender === "fem"
|
||||
&& <span style={{ margin: "0 0.2rem" }}><strong>feminine</strong></span>}
|
||||
{selection.numberCanChange && selection.number === "plural"
|
||||
&& <span style={{ marginLeft: "0 0.2rem" }}><strong>plural</strong></span>}
|
||||
</div>}
|
||||
{showHint && <EntryCategoryTip entry={entry} />}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
function EntryCategoryTip({ entry }: { entry: T.AdjectiveEntry | T.NounEntry }) {
|
||||
const pattern = getInflectionPattern(entry);
|
||||
return <div className="badge bg-light small">
|
||||
{HumanReadableInflectionPattern(pattern, opts)}
|
||||
</div>;
|
||||
}
|
||||
|
||||
export default WordCard;
|
|
@ -10,6 +10,7 @@ import InflectionPatterns from "./sub-cores/InflectionPatterns";
|
|||
import InflectionsWriting from "./sub-cores/InflectionsWriting";
|
||||
import PerfectVerbsIntransitive from "./sub-cores/PerfectGame";
|
||||
import NPAdjWriting from "./sub-cores/NPAdjGame";
|
||||
import EPAdjGame from "./sub-cores/EPAdjGame";
|
||||
|
||||
|
||||
// NOUNS
|
||||
|
@ -398,8 +399,22 @@ export const perfectGameMix = makeGameRecord({
|
|||
});
|
||||
|
||||
// ADJECTIVES
|
||||
export const epWithAdjectivesHints = makeGameRecord({
|
||||
title: "Write the adjective to match the subject (with inf. pattern hints)",
|
||||
id: "adjective-predicate-hints",
|
||||
link: "/inflection/inflection-patterns/",
|
||||
level: "hints",
|
||||
SubCore: EPAdjGame,
|
||||
});
|
||||
export const epWithAdjectives = makeGameRecord({
|
||||
title: "Write the predicate adjective to match the subject",
|
||||
id: "adjective-predicate",
|
||||
link: "/inflection/inflection-patterns/",
|
||||
level: "no-hints",
|
||||
SubCore: EPAdjGame,
|
||||
});
|
||||
export const npWithAdjectivesHints = makeGameRecord({
|
||||
title: "Write the adjective and noun togehter (with inflection hints)",
|
||||
title: "Write the adjective and noun togehter (with inf. pattern hints)",
|
||||
id: "adjective-nps-hints",
|
||||
link: "/phrase-structure/np/",
|
||||
level: "hints",
|
||||
|
@ -493,6 +508,8 @@ const games: { chapter: string, items: GameRecord[] }[] = [
|
|||
{
|
||||
chapter: "Adjectives",
|
||||
items: [
|
||||
epWithAdjectivesHints,
|
||||
epWithAdjectives,
|
||||
npWithAdjectivesHints,
|
||||
npWithAdjectivesNoHints,
|
||||
],
|
||||
|
|
|
@ -0,0 +1,224 @@
|
|||
import { useState } from "react";
|
||||
import {
|
||||
comparePs,
|
||||
} from "../../lib/game-utils";
|
||||
import GameCore from "../GameCore";
|
||||
import {
|
||||
Types as T,
|
||||
renderEP,
|
||||
compileEP,
|
||||
randFromArray,
|
||||
defaultTextOptions as opts,
|
||||
Examples,
|
||||
blank,
|
||||
isPashtoScript,
|
||||
} from "@lingdocs/ps-react";
|
||||
import { wordQuery } from "../../words/words";
|
||||
import { makePool } from "../../lib/pool";
|
||||
import { getPredicateSelectionFromBlocks } from "@lingdocs/ps-react/dist/lib/src/phrase-building/blocks-utils";
|
||||
import WordCard from "../../components/WordCard";
|
||||
|
||||
const amount = 12;
|
||||
const timeLimit = 140;
|
||||
|
||||
const pronouns: T.Person[] = [
|
||||
0, 1, 2, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 11,
|
||||
];
|
||||
|
||||
const adjectives = wordQuery("adjectives", [
|
||||
"muR",
|
||||
"sheen",
|
||||
"soor",
|
||||
"rixtooney",
|
||||
"stuRey",
|
||||
"ghuT",
|
||||
"xu",
|
||||
"khufa",
|
||||
"takRa",
|
||||
"puT",
|
||||
"tuGey",
|
||||
"koochney",
|
||||
"pradey",
|
||||
"zoR",
|
||||
"moR",
|
||||
"khoG",
|
||||
"droond",
|
||||
"loomRey",
|
||||
"Roond",
|
||||
"prot",
|
||||
"soR",
|
||||
"post",
|
||||
"pokh",
|
||||
"rooN",
|
||||
"woR",
|
||||
"kooN",
|
||||
"koG",
|
||||
]);
|
||||
|
||||
type Question = {
|
||||
EPS: T.EPSelectionComplete,
|
||||
phrase: { ps: T.PsString[], e?: string[] },
|
||||
adjective: T.Rendered<T.AdjectiveSelection>,
|
||||
};
|
||||
|
||||
export default function EPAdjGame({ inChapter, id, link, level }: { inChapter: boolean, id: string, link: string, level: "hints" | "no-hints" }) {
|
||||
const pronounPool = makePool(pronouns);
|
||||
const adjPool = makePool(adjectives);
|
||||
function getQuestion(): Question {
|
||||
const subject: T.NPSelection = {
|
||||
type: "NP",
|
||||
selection: {
|
||||
type: "pronoun",
|
||||
person: pronounPool(),
|
||||
distance: randFromArray(["far", "far", "near"]),
|
||||
},
|
||||
};
|
||||
const EPS = makeEPS(subject, adjPool(), "present");
|
||||
const EP = renderEP(EPS);
|
||||
const compiled = compileEP(
|
||||
EP,
|
||||
true,
|
||||
{ predicate: true },
|
||||
);
|
||||
const phrase = {
|
||||
ps: compiled.ps,
|
||||
e: compiled.e,
|
||||
};
|
||||
return {
|
||||
EPS,
|
||||
phrase,
|
||||
adjective: getAdjectiveFromRendered(EP),
|
||||
};
|
||||
};
|
||||
|
||||
function Display({ question, callback }: QuestionDisplayProps<Question>) {
|
||||
const [answer, setAnswer] = useState<string>("");
|
||||
const handleInput = ({ target: { value }}: React.ChangeEvent<HTMLInputElement>) => {
|
||||
setAnswer(value);
|
||||
}
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
const correct = comparePs(answer, question.adjective.ps);
|
||||
if (correct) {
|
||||
setAnswer("");
|
||||
}
|
||||
callback(correct);
|
||||
}
|
||||
|
||||
return <div>
|
||||
<div className="mb-2" style={{ maxWidth: "300px", margin: "0 auto" }}>
|
||||
<Examples lineHeight={1} opts={opts}>{
|
||||
addUserAnswer(answer, question.phrase.ps[0])
|
||||
}</Examples>
|
||||
{question.phrase.e && question.phrase.e.map((e, i) => (
|
||||
<div key={e+i} className="text-muted">{e}</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="d-flex flex-row justify-content-center mb-3">
|
||||
<WordCard
|
||||
entry={question.adjective.entry}
|
||||
showHint={level === "hints"}
|
||||
selection={undefined}
|
||||
/>
|
||||
</div>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="my-1" style={{ maxWidth: "200px", margin: "0 auto" }}>
|
||||
<input
|
||||
type="text"
|
||||
className="form-control"
|
||||
autoComplete="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
dir="auto"
|
||||
value={answer}
|
||||
onChange={handleInput}
|
||||
/>
|
||||
</div>
|
||||
<div className="text-center my-2">
|
||||
<button className="btn btn-primary" type="submit">submit ↵</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
}
|
||||
|
||||
function Instructions() {
|
||||
return <div>
|
||||
<p className="lead">
|
||||
Fill in the blank with the correct inflection of the adjective
|
||||
</p>
|
||||
</div>;
|
||||
}
|
||||
|
||||
return <GameCore
|
||||
inChapter={inChapter}
|
||||
studyLink={link}
|
||||
getQuestion={getQuestion}
|
||||
id={id}
|
||||
Display={Display}
|
||||
DisplayCorrectAnswer={DisplayCorrectAnswer}
|
||||
timeLimit={timeLimit}
|
||||
amount={amount}
|
||||
Instructions={Instructions}
|
||||
/>
|
||||
};
|
||||
|
||||
function DisplayCorrectAnswer({ question }: { question: Question }): JSX.Element {
|
||||
return <div>
|
||||
<div>
|
||||
{question.adjective.ps.reduce(((accum, curr, i): JSX.Element[] => (
|
||||
[
|
||||
...accum,
|
||||
...i > 0 ? [<span className="text-muted"> or </span>] : [],
|
||||
<span key={i}>{curr.p}</span>,
|
||||
]
|
||||
)), [] as JSX.Element[])}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
function addUserAnswer(a: string, ps: T.PsString): T.PsString {
|
||||
if (!a) return ps;
|
||||
const field = isPashtoScript(a) ? "p" : "f";
|
||||
return {
|
||||
...ps,
|
||||
[field]: ps[field].replace(blank[field], a),
|
||||
};
|
||||
}
|
||||
|
||||
function getAdjectiveFromRendered(EP: T.EPRendered): T.Rendered<T.AdjectiveSelection> {
|
||||
const pred = getPredicateSelectionFromBlocks(EP.blocks);
|
||||
if (pred.selection.type !== "complement" || pred.selection.selection.type !== "adjective") {
|
||||
throw new Error("adjective not found in predicate");
|
||||
}
|
||||
return pred.selection.selection;
|
||||
}
|
||||
|
||||
function makeEPS(subject: T.NPSelection, predicate: T.AdjectiveEntry, tense: T.EquativeTense): T.EPSelectionComplete {
|
||||
return {
|
||||
blocks: [
|
||||
{
|
||||
key: Math.random(),
|
||||
block: {
|
||||
type: "subjectSelection",
|
||||
selection: subject,
|
||||
},
|
||||
},
|
||||
],
|
||||
predicate: {
|
||||
type: "predicateSelection",
|
||||
selection: {
|
||||
type: "complement",
|
||||
selection: {
|
||||
type: "adjective",
|
||||
entry: predicate,
|
||||
sandwich: undefined,
|
||||
},
|
||||
},
|
||||
},
|
||||
equative: {
|
||||
tense,
|
||||
negative: false,
|
||||
},
|
||||
omitSubject: false,
|
||||
};
|
||||
}
|
|
@ -1,19 +1,14 @@
|
|||
import GameCore from "../GameCore";
|
||||
import {
|
||||
Types as T,
|
||||
Examples,
|
||||
defaultTextOptions as opts,
|
||||
firstVariation,
|
||||
renderNPSelection,
|
||||
getEnglishFromRendered,
|
||||
removeFVarients,
|
||||
concatPsString,
|
||||
getInflectionPattern,
|
||||
HumanReadableInflectionPattern,
|
||||
} from "@lingdocs/ps-react";
|
||||
import { makeNPAdjGenerator } from "../../lib/np-adj-generator";
|
||||
import { useState } from "react";
|
||||
import { comparePs } from "../../lib/game-utils";
|
||||
import WordCard from "../../components/WordCard";
|
||||
|
||||
const amount = 15;
|
||||
const timeLimit = 230;
|
||||
|
@ -38,9 +33,6 @@ const NPAdjWriting: GameSubCore<Level> = ({ inChapter, id, link, level }: {
|
|||
}) => {
|
||||
const npPool = makeNPAdjGenerator();
|
||||
|
||||
// todo زړې ډاکټرې should work!
|
||||
// feminineplural space issue
|
||||
|
||||
function getQuestion(): Question {
|
||||
const np = npPool();
|
||||
const rendered = renderNPSelection(np, false, false, "subject", "none", false);
|
||||
|
@ -153,41 +145,4 @@ function DisplayCorrectAnswer({ question }: { question: Question }): JSX.Element
|
|||
</div>;
|
||||
}
|
||||
|
||||
function WordCard({ showHint, entry, selection }: {
|
||||
showHint: boolean
|
||||
} & ({
|
||||
entry: T.AdjectiveEntry,
|
||||
selection: undefined,
|
||||
} | {
|
||||
entry: T.NounEntry,
|
||||
selection: T.NounSelection,
|
||||
})) {
|
||||
const e = removeFVarients(entry);
|
||||
return <div className="card ml-2" style={{ minWidth: "10rem"}}>
|
||||
<div className="card-body" style={{ padding: "0.75rem" }}>
|
||||
<Examples opts={opts}>{[
|
||||
{
|
||||
p: e.p,
|
||||
f: e.f,
|
||||
e: `${firstVariation(e.e)} - ${e.c}`,
|
||||
}
|
||||
]}</Examples>
|
||||
{selection && <div style={{ marginTop: "-0.75rem"}}>
|
||||
{selection.genderCanChange && selection.gender === "fem"
|
||||
&& <span style={{ margin: "0 0.2rem" }}><strong>feminine</strong></span>}
|
||||
{selection.numberCanChange && selection.number === "plural"
|
||||
&& <span style={{ marginLeft: "0 0.2rem" }}><strong>plural</strong></span>}
|
||||
</div>}
|
||||
{showHint && <EntryCategoryTip entry={entry} />}
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
|
||||
function EntryCategoryTip({ entry }: { entry: T.AdjectiveEntry | T.NounEntry }) {
|
||||
const pattern = getInflectionPattern(entry);
|
||||
return <div className="badge bg-light small">
|
||||
{HumanReadableInflectionPattern(pattern, opts)}
|
||||
</div>;
|
||||
}
|
||||
|
||||
export default NPAdjWriting;
|
||||
|
|
|
@ -350,22 +350,7 @@ function DisplayCorrectAnswer({ question }: { question: Question }): JSX.Element
|
|||
<div><strong>{verbHasBa(question.rendered) ? "with" : "without"}</strong> a <InlinePs opts={opts}>{grammarUnits.baParticle}</InlinePs> in the kids' section.</div>
|
||||
</div>;
|
||||
}
|
||||
// function modExs(exs: T.PsString[], withBa: boolean): { p: JSX.Element, f: JSX.Element }[] {
|
||||
// return exs.map(ps => {
|
||||
// if (!ps.p.includes(" ___ ")) {
|
||||
// return {
|
||||
// p: <>{ps.p}</>,
|
||||
// f: <>{ps.f}</>,
|
||||
// };
|
||||
// }
|
||||
// const splitP = ps.p.split(" ___ ");
|
||||
// const splitF = ps.f.split(" ___ ");
|
||||
// return {
|
||||
// p: <>{splitP[0]} <span style={{ color: kidsColor }}>{withBa ? "به" : "__"}</span> {splitP[1]}</>,
|
||||
// f: <>{splitF[0]} <span style={{ color: kidsColor }}>{withBa ? "ba" : "__"}</span> {splitF[1]}</>,
|
||||
// };
|
||||
// });
|
||||
// }
|
||||
|
||||
|
||||
function addUserAnswer(a: { withBa: boolean, answer: string }, ps: T.PsString): T.PsString {
|
||||
function addBa(x: T.PsString) {
|
||||
|
|
|
@ -58,7 +58,6 @@ const adjectives = wordQuery("adjectives", [
|
|||
"droond",
|
||||
"loomRey",
|
||||
"Roond",
|
||||
"droond",
|
||||
"prot",
|
||||
"soR",
|
||||
"post",
|
||||
|
|
|
@ -2726,10 +2726,10 @@
|
|||
rambda "^6.7.0"
|
||||
react-select "^5.2.2"
|
||||
|
||||
"@lingdocs/ps-react@^5.3.1":
|
||||
version "5.3.1"
|
||||
resolved "https://npm.lingdocs.com/@lingdocs%2fps-react/-/ps-react-5.3.1.tgz#a8836d00df5ca884d8b26dd4caae7c720269ce26"
|
||||
integrity sha512-JY0BQLnxKNjxqHlf7uvmH2ehmbbPvGoWdcxK68ZEZbwbXP0WXHmyFUji6hB9oRHtwrE8MS7guVX0e3/eZTolEA==
|
||||
"@lingdocs/ps-react@^5.3.3":
|
||||
version "5.3.3"
|
||||
resolved "https://npm.lingdocs.com/@lingdocs%2fps-react/-/ps-react-5.3.3.tgz#05066c27059b5133dc0028d733d6dddfbfc9f9b0"
|
||||
integrity sha512-qsX9iRqSc62JGDuBNvddfZgX3Skk5MM8XtuaydnyK3A7LZrP9VuiJZ0+k6zvi2shi+Gg52aAEPJstEieycBKrA==
|
||||
dependencies:
|
||||
"@formkit/auto-animate" "^1.0.0-beta.3"
|
||||
classnames "^2.2.6"
|
||||
|
|
Loading…
Reference in New Issue