adjective game
This commit is contained in:
parent
cd774fc304
commit
1550409440
|
@ -7,7 +7,7 @@
|
||||||
"@formkit/auto-animate": "^1.0.0-beta.1",
|
"@formkit/auto-animate": "^1.0.0-beta.1",
|
||||||
"@fortawesome/fontawesome-free": "^5.15.4",
|
"@fortawesome/fontawesome-free": "^5.15.4",
|
||||||
"@lingdocs/lingdocs-main": "^0.3.3",
|
"@lingdocs/lingdocs-main": "^0.3.3",
|
||||||
"@lingdocs/ps-react": "^5.3.0",
|
"@lingdocs/ps-react": "^5.3.1",
|
||||||
"@testing-library/jest-dom": "^5.11.4",
|
"@testing-library/jest-dom": "^5.11.4",
|
||||||
"@testing-library/react": "^11.1.0",
|
"@testing-library/react": "^11.1.0",
|
||||||
"@testing-library/user-event": "^12.1.10",
|
"@testing-library/user-event": "^12.1.10",
|
||||||
|
|
|
@ -94,6 +94,8 @@ Now we have two words, but it's still **one NP**, one building block. We can add
|
||||||
}
|
}
|
||||||
}</EditableBlock>
|
}</EditableBlock>
|
||||||
|
|
||||||
|
It's important to note that the adjective will <Link to="/inflection/inflection-patterns/">inflect</Link> according to the noun it's attached to.
|
||||||
|
|
||||||
#### Adding a possesor
|
#### Adding a possesor
|
||||||
|
|
||||||
We can also add a **possesor** by adding another NP <Link to="/sandwiches/sandwiches/">sandwiched</Link> in with a <InlinePs opts={opts} ps={{ p: "د", f: "du", e: "of"}} />. (Notice that the word sandwiched in there will <Link to="/inflection/inflection-intro/">inflect</Link> if possible.) Now we have a NP inside of an NP, but it's still all **one NP** or **one building block**.
|
We can also add a **possesor** by adding another NP <Link to="/sandwiches/sandwiches/">sandwiched</Link> in with a <InlinePs opts={opts} ps={{ p: "د", f: "du", e: "of"}} />. (Notice that the word sandwiched in there will <Link to="/inflection/inflection-intro/">inflect</Link> if possible.) Now we have a NP inside of an NP, but it's still all **one NP** or **one building block**.
|
||||||
|
|
|
@ -9,6 +9,7 @@ import VerbFormulas from "./sub-cores/VerbFormulas";
|
||||||
import InflectionPatterns from "./sub-cores/InflectionPatterns";
|
import InflectionPatterns from "./sub-cores/InflectionPatterns";
|
||||||
import InflectionsWriting from "./sub-cores/InflectionsWriting";
|
import InflectionsWriting from "./sub-cores/InflectionsWriting";
|
||||||
import PerfectVerbsIntransitive from "./sub-cores/PerfectGame";
|
import PerfectVerbsIntransitive from "./sub-cores/PerfectGame";
|
||||||
|
import NPAdjWriting from "./sub-cores/NPAdjGame";
|
||||||
|
|
||||||
|
|
||||||
// NOUNS
|
// NOUNS
|
||||||
|
@ -396,6 +397,22 @@ export const perfectGameMix = makeGameRecord({
|
||||||
SubCore: PerfectVerbsIntransitive,
|
SubCore: PerfectVerbsIntransitive,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ADJECTIVES
|
||||||
|
export const npWithAdjectivesHints = makeGameRecord({
|
||||||
|
title: "Write the adjective and noun togehter (with inflection hints)",
|
||||||
|
id: "adjective-nps-hints",
|
||||||
|
link: "/phrase-structure/np/",
|
||||||
|
level: "hints",
|
||||||
|
SubCore: NPAdjWriting,
|
||||||
|
});
|
||||||
|
export const npWithAdjectivesNoHints = makeGameRecord({
|
||||||
|
title: "Write the adjective and noun togehter",
|
||||||
|
id: "adjective-nps-no-hints",
|
||||||
|
link: "/phrase-structure/np/",
|
||||||
|
level: "no-hints",
|
||||||
|
SubCore: NPAdjWriting,
|
||||||
|
});
|
||||||
|
|
||||||
const games: { chapter: string, items: GameRecord[] }[] = [
|
const games: { chapter: string, items: GameRecord[] }[] = [
|
||||||
{
|
{
|
||||||
chapter: "Nouns",
|
chapter: "Nouns",
|
||||||
|
@ -473,6 +490,13 @@ const games: { chapter: string, items: GameRecord[] }[] = [
|
||||||
perfectGameMix,
|
perfectGameMix,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
chapter: "Adjectives",
|
||||||
|
items: [
|
||||||
|
npWithAdjectivesHints,
|
||||||
|
npWithAdjectivesNoHints,
|
||||||
|
],
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// check to make sure we have no duplicate game keys
|
// check to make sure we have no duplicate game keys
|
||||||
|
|
|
@ -143,7 +143,7 @@ function DisplayCorrectAnswer({ question }: { question: Question }): JSX.Element
|
||||||
[
|
[
|
||||||
...accum,
|
...accum,
|
||||||
...i > 0 ? [<span className="text-muted"> or </span>] : [],
|
...i > 0 ? [<span className="text-muted"> or </span>] : [],
|
||||||
<span>{curr.p}</span>,
|
<span key={i}>{curr.p}</span>,
|
||||||
]
|
]
|
||||||
)), [] as JSX.Element[])}
|
)), [] as JSX.Element[])}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,193 @@
|
||||||
|
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";
|
||||||
|
|
||||||
|
const amount = 15;
|
||||||
|
const timeLimit = 230;
|
||||||
|
|
||||||
|
type Question = {
|
||||||
|
selection: T.NPSelection,
|
||||||
|
answer: T.PsString[],
|
||||||
|
english: string,
|
||||||
|
};
|
||||||
|
|
||||||
|
type Level = "hints" | "no-hints";
|
||||||
|
|
||||||
|
// LEVELS
|
||||||
|
// - without plurals
|
||||||
|
// - with inflection category hinting
|
||||||
|
|
||||||
|
const NPAdjWriting: GameSubCore<Level> = ({ inChapter, id, link, level }: {
|
||||||
|
inChapter: boolean,
|
||||||
|
id: string,
|
||||||
|
link: string,
|
||||||
|
level: 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);
|
||||||
|
const renderedAdj: T.Rendered<T.AdjectiveSelection> | undefined = rendered.selection.adjectives && rendered.selection.adjectives[0];
|
||||||
|
if (!renderedAdj) {
|
||||||
|
throw new Error("error getting rendered adjective");
|
||||||
|
}
|
||||||
|
const answer = renderedAdj.ps.flatMap((adjPs) => (
|
||||||
|
rendered.selection.ps.map((nounPs) => (
|
||||||
|
concatPsString(adjPs, " ", nounPs)
|
||||||
|
))
|
||||||
|
));
|
||||||
|
return {
|
||||||
|
selection: np,
|
||||||
|
answer,
|
||||||
|
english: getEnglishFromRendered(rendered) || "ERROR",
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function Display({ question, callback }: QuestionDisplayProps<Question>) {
|
||||||
|
const [answer, setAnswer] = useState<string>("");
|
||||||
|
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const correct = comparePs(answer, question.answer);
|
||||||
|
if (correct) {
|
||||||
|
setAnswer("");
|
||||||
|
}
|
||||||
|
callback(correct);
|
||||||
|
}
|
||||||
|
if (question.selection.type !== "NP" || question.selection.selection.type !== "noun") {
|
||||||
|
throw new Error("QUESTION ERROR");
|
||||||
|
}
|
||||||
|
const nounEntry = question.selection.selection.entry;
|
||||||
|
const adjEntry: T.AdjectiveEntry | undefined = question.selection.selection.adjectives[0]?.entry;
|
||||||
|
if (!adjEntry) {
|
||||||
|
throw new Error("QUESTION ERROR - MISSING ADJECTIVE");
|
||||||
|
}
|
||||||
|
const handleInput = ({ target: { value }}: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
setAnswer(value);
|
||||||
|
}
|
||||||
|
return <div>
|
||||||
|
<div className="my-2" style={{ maxWidth: "300px", margin: "0 auto" }}>
|
||||||
|
<div className="d-flex flex-row justify-content-center">
|
||||||
|
<WordCard
|
||||||
|
showHint={level === "hints"}
|
||||||
|
entry={adjEntry}
|
||||||
|
selection={undefined}
|
||||||
|
/>
|
||||||
|
<WordCard
|
||||||
|
showHint={level === "hints"}
|
||||||
|
entry={nounEntry}
|
||||||
|
selection={question.selection.selection}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="my-3 h5">
|
||||||
|
{question.english}
|
||||||
|
</div>
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<div className="mt-2 mb-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-3">
|
||||||
|
<button className="btn btn-primary" type="submit">submit ↵</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
function Instructions() {
|
||||||
|
return <div>
|
||||||
|
<p className="lead">Write the adjective and noun together with the proper inflections.</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 {
|
||||||
|
// TODO: extract this reduces for the or, or different variations, used in VerbGame (etc.?)
|
||||||
|
return <div>
|
||||||
|
<div>
|
||||||
|
{question.answer.reduce(((accum, curr, i): JSX.Element[] => (
|
||||||
|
[
|
||||||
|
...accum,
|
||||||
|
...i > 0 ? [<span className="text-muted"> or </span>] : [],
|
||||||
|
<span key={i}>{curr.p} - {curr.f}</span>,
|
||||||
|
]
|
||||||
|
)), [] as JSX.Element[])}
|
||||||
|
</div>
|
||||||
|
</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;
|
|
@ -342,7 +342,7 @@ function DisplayCorrectAnswer({ question }: { question: Question }): JSX.Element
|
||||||
[
|
[
|
||||||
...accum,
|
...accum,
|
||||||
...i > 0 ? [<span className="text-muted"> or </span>] : [],
|
...i > 0 ? [<span className="text-muted"> or </span>] : [],
|
||||||
<span>{curr.p} - {curr.f}</span>,
|
<span key={i}>{curr.p} - {curr.f}</span>,
|
||||||
]
|
]
|
||||||
)), [] as JSX.Element[])}
|
)), [] as JSX.Element[])}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -343,7 +343,7 @@ function DisplayCorrectAnswer({ question }: { question: Question }): JSX.Element
|
||||||
[
|
[
|
||||||
...accum,
|
...accum,
|
||||||
...i > 0 ? [<span className="text-muted"> or </span>] : [],
|
...i > 0 ? [<span className="text-muted"> or </span>] : [],
|
||||||
<span>{curr.p} - {curr.f}</span>,
|
<span key={i}>{curr.p} - {curr.f}</span>,
|
||||||
]
|
]
|
||||||
)), [] as JSX.Element[])}
|
)), [] as JSX.Element[])}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -28,7 +28,8 @@ export function compareF(input: string, answer: string): boolean {
|
||||||
return inp === (hasAccents(inp) ? ans : removeAccents(ans));
|
return inp === (hasAccents(inp) ? ans : removeAccents(ans));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function comparePs(input: string, answer: T.SingleOrLengthOpts<T.PsString | T.PsString[]>): boolean {
|
export function comparePs(inputRaw: string, answer: T.SingleOrLengthOpts<T.PsString | T.PsString[]>): boolean {
|
||||||
|
const input = inputRaw.replace(/\s+/g, " ");
|
||||||
if ("long" in answer) {
|
if ("long" in answer) {
|
||||||
return comparePs(input, flattenLengths(answer));
|
return comparePs(input, flattenLengths(answer));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
import {
|
||||||
|
Types as T,
|
||||||
|
makeNounSelection,
|
||||||
|
makeAdjectiveSelection,
|
||||||
|
randFromArray,
|
||||||
|
} from "@lingdocs/ps-react";
|
||||||
|
import { makePool } from "./pool";
|
||||||
|
import { wordQuery } from "../words/words";
|
||||||
|
|
||||||
|
const nouns = wordQuery("nouns", [
|
||||||
|
"saRey",
|
||||||
|
"xudza",
|
||||||
|
"maashoom",
|
||||||
|
"Ustaaz",
|
||||||
|
"puxtoon",
|
||||||
|
"DaakTar",
|
||||||
|
"halik",
|
||||||
|
"tajriba",
|
||||||
|
"melma",
|
||||||
|
"khabura",
|
||||||
|
"kitaab",
|
||||||
|
"oobu",
|
||||||
|
"korba",
|
||||||
|
"shpoon",
|
||||||
|
"gaawanDey",
|
||||||
|
"lmasey",
|
||||||
|
"lobghaaRey",
|
||||||
|
"sandurghaaRey",
|
||||||
|
"malgurey",
|
||||||
|
"shpoonkey",
|
||||||
|
"khalk",
|
||||||
|
"ghul",
|
||||||
|
"khur",
|
||||||
|
]);
|
||||||
|
|
||||||
|
const adjectives = wordQuery("adjectives", [
|
||||||
|
"muR",
|
||||||
|
"sheen",
|
||||||
|
"soor",
|
||||||
|
"rixtooney",
|
||||||
|
"pakhwaaney",
|
||||||
|
"stuRey",
|
||||||
|
"ooGd",
|
||||||
|
"ghuT",
|
||||||
|
"xu",
|
||||||
|
"khufa",
|
||||||
|
"takRa",
|
||||||
|
"puT",
|
||||||
|
"tuGey",
|
||||||
|
"koochney",
|
||||||
|
"wroostey",
|
||||||
|
"pradey",
|
||||||
|
"zoR",
|
||||||
|
"moR",
|
||||||
|
"treekh",
|
||||||
|
"oom",
|
||||||
|
"khoG",
|
||||||
|
"droond",
|
||||||
|
"loomRey",
|
||||||
|
"Roond",
|
||||||
|
"droond",
|
||||||
|
"prot",
|
||||||
|
"soR",
|
||||||
|
"post",
|
||||||
|
"pokh",
|
||||||
|
"rooN",
|
||||||
|
"woR",
|
||||||
|
"tod",
|
||||||
|
"khpor",
|
||||||
|
"kooN",
|
||||||
|
"koG",
|
||||||
|
"zeeG",
|
||||||
|
]);
|
||||||
|
|
||||||
|
export function makeNPAdjGenerator(avoidPlurals?: boolean): () => T.NPSelection {
|
||||||
|
const nounPool = makePool(nouns);
|
||||||
|
const adjPool = makePool(adjectives);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
const ns = makeNounSelection(nounPool(), undefined);
|
||||||
|
const selection: T.NounSelection = {
|
||||||
|
...ns,
|
||||||
|
adjectives: [makeAdjectiveSelection(adjPool())],
|
||||||
|
...(ns.numberCanChange && !avoidPlurals) ? {
|
||||||
|
number: randFromArray(["singular", "plural", "plural", "plural", "singular"]),
|
||||||
|
} : {},
|
||||||
|
...ns.genderCanChange ? {
|
||||||
|
gender: randFromArray(["masc", "fem", "fem", "fem", "masc"]),
|
||||||
|
} : {},
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
type: "NP",
|
||||||
|
selection,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ module.exports = [
|
||||||
1527822788, // بېګاته - begáata
|
1527822788, // بېګاته - begáata
|
||||||
1527812183, // ورپام - wărpaam
|
1527812183, // ورپام - wărpaam
|
||||||
1527814711, // لنډ پر لنډه - lanD par lanDa
|
1527814711, // لنډ پر لنډه - lanD par lanDa
|
||||||
1527821930, // بالبدیهه - bilbadeehá
|
|
||||||
1527814164, // دېخوا - dekhwaa
|
1527814164, // دېخوا - dekhwaa
|
||||||
1527815160, // پرون - paroon
|
1527815160, // پرون - paroon
|
||||||
1623688539364, // ګانګوړ - gaangóR, gaangwÚR
|
1623688539364, // ګانګوړ - gaangóR, gaangwÚR
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
module.exports = [
|
module.exports = [
|
||||||
1527812797, // xudza
|
1527815329, // tajriba
|
||||||
|
1527812797, // xudza
|
||||||
|
1527812766, // khabura
|
||||||
1527816466, // صلح - sUlha
|
1527816466, // صلح - sUlha
|
||||||
1527816589, // طرح - tarha
|
1527816589, // طرح - tarha
|
||||||
1589023873660, // فتح - fathá
|
1589023873660, // فتح - fathá
|
||||||
|
|
|
@ -15,4 +15,5 @@ module.exports = [
|
||||||
1527822725, // لوېشت - lwesht
|
1527822725, // لوېشت - lwesht
|
||||||
1527811609, // منګل - mangul
|
1527811609, // منګل - mangul
|
||||||
1527821684, // ورېځ - wurédz
|
1527821684, // ورېځ - wurédz
|
||||||
|
1527815129, // oobu
|
||||||
];
|
];
|
|
@ -1,4 +1,6 @@
|
||||||
module.exports = [
|
module.exports = [
|
||||||
|
1527812342, // khalk
|
||||||
|
1527814694, // mawaad
|
||||||
1527815177, // پلار
|
1527815177, // پلار
|
||||||
1527812828, // کور
|
1527812828, // کور
|
||||||
1527812432, // آسمان - aasmaan
|
1527812432, // آسمان - aasmaan
|
||||||
|
|
|
@ -12,7 +12,6 @@ module.exports = [
|
||||||
1527818402, // اتلولي - atalwalée
|
1527818402, // اتلولي - atalwalée
|
||||||
1527814060, // اساني - asaanee
|
1527814060, // اساني - asaanee
|
||||||
1527821293, // امادګي - amaadagee
|
1527821293, // امادګي - amaadagee
|
||||||
1527819502, // باچهي - baachahee
|
|
||||||
1527820035, // باداري - baadaaree
|
1527820035, // باداري - baadaaree
|
||||||
1527817732, // بدبختي - badbakhtee
|
1527817732, // بدبختي - badbakhtee
|
||||||
1588786872582, // بدنامي - badnaamee
|
1588786872582, // بدنامي - badnaamee
|
||||||
|
|
|
@ -16,4 +16,5 @@ module.exports = [
|
||||||
1527815087, // مړ - muR
|
1527815087, // مړ - muR
|
||||||
1527814151, // مل - mal
|
1527814151, // مل - mal
|
||||||
1527813580, // یو - yo
|
1527813580, // یو - yo
|
||||||
|
1527819902, // zeeG
|
||||||
];
|
];
|
Loading…
Reference in New Issue