really basic present and subjunctive verb games

This commit is contained in:
lingdocs 2022-08-24 16:54:34 +04:00
parent 55512ce788
commit 1c3f9c2f62
7 changed files with 122 additions and 75 deletions

View File

@ -7,7 +7,7 @@
"@formkit/auto-animate": "^1.0.0-beta.1",
"@fortawesome/fontawesome-free": "^5.15.4",
"@lingdocs/lingdocs-main": "^0.3.1",
"@lingdocs/pashto-inflector": "^3.7.6",
"@lingdocs/pashto-inflector": "^3.7.9",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",

View File

@ -13,6 +13,10 @@ import Formula from "../../components/formula/Formula";
import realityGraph from "./reality-graph.svg";
import presentTime from "./present-time.svg";
import BasicVerbShowCase from "./../../components/BasicVerbShowCase";
import {
presentVerbGame,
} from "../../games/games";
import GameDisplay from "../../games/GameDisplay";
The first verb form we'll learn is the **present**. This will be the first tool in our toolbox of verb forms. 🧰 With each verb form we'll learn two things:
@ -118,4 +122,6 @@ Here are some examples of how the present form is used in different situations:
},
])}</Examples>
<GameDisplay record={presentVerbGame} />

View File

@ -15,6 +15,10 @@ import Formula from "../../components/formula/Formula";
import presentInReality from "./present-in-reality.svg";
import subjunctiveAboveReality from "./subjunctive-above-reality.svg";
import BasicVerbShowCase from "../../components/BasicVerbShowCase";
import {
subjunctiveVerbGame,
} from "../../games/games";
import GameDisplay from "../../games/GameDisplay";
The **subjunctive** is a very important verb form in Pashto, but it's often ignored by English-speaking learners because we don't really have anything like it in English. So, we need to understand what it is, and then train our brains to reach for it and use it in the right situations!
@ -103,3 +107,5 @@ As you can see, the subjunctive is often used in [subordinate clauses](https://e
- <InlinePs opts={opts} ps={{ p: "په کار دی چې ...", f: "pu kaar dey che ...", e: "It's necessary that ..." }} />
...etc.
<GameDisplay record={subjunctiveVerbGame} />

View File

@ -22,7 +22,13 @@ export const presentVerbGame = makeGameRecord(
"present-verbs-write",
"/verbs/present-verbs/",
(id, link) => () => <VerbGame id={id} level="presentVerb" link={link} />
)
);
export const subjunctiveVerbGame = makeGameRecord(
"Write the subjunctive verb",
"subjunctive-verbs-write",
"/verbs/subjunctive-verbs/",
(id, link) => () => <VerbGame id={id} level="subjunctiveVerb" link={link} />
);
export const nounGenderGame1 = makeGameRecord(
"Identify Noun Genders - Level 1",
@ -149,6 +155,7 @@ const games: { chapter: string, items: GameRecord[] }[] = [
chapter: "Verbs",
items: [
presentVerbGame,
subjunctiveVerbGame,
],
}
];

View File

@ -1,4 +1,4 @@
import { useEffect, useState } from "react";
import { useState } from "react";
import {
comparePs,
makeProgress,
@ -6,26 +6,23 @@ import {
import GameCore from "../GameCore";
import {
Types as T,
Examples,
defaultTextOptions as opts,
typePredicates as tp,
makeNounSelection,
randFromArray,
renderEP,
compileEP,
flattenLengths,
randomPerson,
InlinePs,
grammarUnits,
randomSubjObj,
renderVP,
makeVPSelectionState,
compileVP,
blockUtils,
concatPsString,
isInvalidSubjObjCombo,
} from "@lingdocs/pashto-inflector";
import { basicVerbs, intransitivePast } from "../../content/verbs/basic-present-verbs";
import { psStringEquals } from "@lingdocs/pashto-inflector/dist/lib/p-text-helpers";
import { isThirdPerson } from "@lingdocs/pashto-inflector/dist/lib/phrase-building/vp-tools";
import { maybeShuffleArray } from "../../lib/shuffle-array";
const kidsColor = "#017BFE";
@ -37,6 +34,12 @@ type Question = {
phrase: { ps: T.SingleOrLengthOpts<T.PsString[]>, e?: string[] },
};
const verbs: T.VerbEntry[] = [
{"ts":1527812856,"i":11630,"p":"لیکل","f":"leekul","g":"leekul","e":"to write, draw","c":"v. trans./gramm. trans.","ec":"write,writes,writing,wrote,written"},
{"ts":1527815399,"i":14480,"p":"وهل","f":"wahul","g":"wahul","e":"to hit","c":"v. trans.","tppp":"واهه","tppf":"waahu","ec":"hit,hits,hitting,hit,hit"},
{"ts":1527812275,"i":11608,"p":"لیدل","f":"leedul","g":"leedul","e":"to see","c":"v. trans./gramm. trans.","psp":"وین","psf":"ween","tppp":"لید","tppf":"leed","ec":"see,sees,seeing,saw,seen"},
{"ts":1577049208257,"i":1068,"p":"اورېدل","f":"awredul","g":"awredul","e":"to hear, listen","c":"v. trans./gramm. trans.","psp":"اور","psf":"awr","tppp":"اورېد","tppf":"awred","ec":"hear,hears,hearing,heard"},
].map(entry => ({ entry })) as T.VerbEntry[];
// @ts-ignore
const nouns: T.NounEntry[] = [
{"ts":1527815251,"i":7790,"p":"سړی","f":"saRéy","g":"saRey","e":"man","c":"n. m.","ec":"man","ep":"men"},
@ -61,7 +64,7 @@ const pronounTypes = [
export default function VerbGame({ id, link, level }: { id: string, link: string, level: T.VerbTense }) {
function* questions (): Generator<Current<Question>> {
let pool = [...pronounTypes];
function makeRandPronoun(): T.PronounSelection {
function getRandPersFromPool(): T.Person {
let person: T.Person;
do {
person = randomPerson();
@ -71,11 +74,7 @@ export default function VerbGame({ id, link, level }: { id: string, link: string
if (pool.length === 0) {
pool = pronounTypes;
}
return {
type: "pronoun",
distance: "far",
person,
};
return person;
}
function makeRandomNoun(): T.NounSelection {
const n = makeNounSelection(randFromArray(nouns), undefined);
@ -86,43 +85,48 @@ export default function VerbGame({ id, link, level }: { id: string, link: string
};
}
function makeRandomVPS(l: T.VerbTense): T.VPSelectionComplete {
function makePronoun(p: T.Person): T.PronounSelection {
function personToNPSelection(p: T.Person): T.NPSelection {
if (!isThirdPerson(p)) {
return {
type: "NP",
selection: randFromArray([
() => makePronounS(p),
makeRandomNoun,
() => makePronounS(p),
])(),
};
}
return {
type: "NP",
selection: makePronounS(p),
};
}
function makePronounS(p: T.Person): T.PronounSelection {
return {
type: "pronoun",
person: p,
distance: "far",
distance: randFromArray(["far", "near", "far"]),
};
}
function makeNPSelection(pr: T.PronounSelection): T.NPSelection {
return {
type: "NP",
selection: pr,
};
}
const verb = randFromArray(basicVerbs);
const { subj, obj } = randomSubjObj();
// const subj: T.NPSelection = {
// type: "NP",
// selection: randFromArray([
// makeRandPronoun,
// makeRandPronoun,
// makeRandomNoun,
// makeRandPronoun,
// ])(),
// };
const verb = randFromArray(verbs);
const subj = getRandPersFromPool();
let obj: T.Person;
do {
obj = randomPerson();
} while (isInvalidSubjObjCombo(subj, obj));
// const tense = (l === "allIdentify" || l === "allProduce")
// ? randFromArray(tenses)
// : l;
const tense = l;
return makeVPS({
verb,
subject: makeNPSelection(makePronoun(subj)),
object: makeNPSelection(makePronoun(obj)),
subject: personToNPSelection(subj),
object: personToNPSelection(obj),
tense,
});
}
for (let i = 0; i < amount; i++) {
const VPS = makeRandomVPS("presentVerb");
const VPS = makeRandomVPS(level);
const VP = renderVP(VPS);
const compiled = compileVP(
VP,
@ -144,7 +148,6 @@ export default function VerbGame({ id, link, level }: { id: string, link: string
};
}
function Display({ question, callback }: QuestionDisplayProps<Question>) {
const [answer, setAnswer] = useState<string>("");
const [withBa, setWithBa] = useState<boolean>(false);
@ -207,7 +210,7 @@ export default function VerbGame({ id, link, level }: { id: string, link: string
function Instructions() {
return <div>
<p className="lead">Write the present verb to complete the phrase</p>
<p className="lead">Write the {humanReadableVerbTense(level)} verb to complete the phrase</p>
</div>
}
@ -221,12 +224,12 @@ export default function VerbGame({ id, link, level }: { id: string, link: string
/>
};
function QuestionDisplay(question: Question) {
function QuestionDisplay({ question }: { question: Question }) {
const ps = flattenLengths(question.phrase.ps)[0];
return <div>
return <div className="mb-3">
<div>{ps.p}</div>
<div>{ps.f}</div>
{question.phrase.e && <div>
{question.phrase.e && <div className="text-muted mt-2">
{question.phrase.e.map(x => <div key={Math.random()}>
{x}
</div>)}
@ -248,33 +251,40 @@ function makeCorrectAnswer(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 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 humanReadableTense(tense: T.EquativeTense | "allProduce"): string {
return tense === "allProduce"
? ""
: tense === "pastSubjunctive"
? "past subjunctive"
: tense === "wouldBe"
? `"would be"`
: tense === "wouldHaveBeen"
? `"would have been"`
: tense;
function humanReadableVerbTense(tense: T.VerbTense): string {
return tense === "presentVerb"
? "present"
: tense === "subjunctiveVerb"
? "subjunctive"
: tense === "imperfectiveFuture"
? "imperfective future"
: tense === "perfectiveFuture"
? "perfective future"
: tense === "perfectivePast"
? "simple past"
: tense === "imperfectivePast"
? "continuous past"
: tense === "habitualImperfectivePast"
? "habitual simple past"
: "habitual continuous past";
}
function makeVPS({ verb, subject, object, tense }: {
@ -284,13 +294,17 @@ function makeVPS({ verb, subject, object, tense }: {
tense: T.VerbTense,
}): T.VPSelectionComplete {
const vps = makeVPSelectionState(verb);
const transitivity = (vps.verb.transitivity === "transitive" && vps.verb.canChangeTransitivity)
? "grammatically transitive"
: vps.verb.transitivity;
return {
...vps,
verb: {
...vps.verb,
transitivity,
tense,
},
blocks: [
blocks: maybeShuffleArray([
{
key: Math.random(),
block: {
@ -302,10 +316,14 @@ function makeVPS({ verb, subject, object, tense }: {
key: Math.random(),
block: {
type: "objectSelection",
selection: object,
selection: transitivity === "intransitive"
? "none"
: transitivity === "grammatically transitive"
? T.Person.ThirdPlurMale
: object,
},
},
],
]),
};
}

View File

@ -1,5 +1,7 @@
// https://stackoverflow.com/a/2450976
import { randFromArray } from "@lingdocs/pashto-inflector";
function shuffleArray<T>(arr: Readonly<Array<T>>): Array<T> {
let currentIndex = arr.length, temporaryValue, randomIndex;
@ -21,4 +23,12 @@ function shuffleArray<T>(arr: Readonly<Array<T>>): Array<T> {
return array;
}
export function maybeShuffleArray<T>(arr: Array<T>): Array<T> {
const shuffle = randFromArray([true, false, true, false, false]);
if (shuffle) {
return shuffleArray(arr);
}
return arr;
}
export default shuffleArray;

View File

@ -1803,10 +1803,10 @@
rambda "^6.7.0"
react-select "^5.2.2"
"@lingdocs/pashto-inflector@^3.7.5":
version "3.7.5"
resolved "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-3.7.5.tgz#6421b88ccf544cdbc7f4cefc66ff75b3b7f1bb44"
integrity sha512-36ULd7ETZBz9/gs2K1s2XJFzEA3kDZfR9rPPN6B5oJvW9yAZXfgaJg9W2jzhodfu2WS3lpQvizis8zQjPioV8w==
"@lingdocs/pashto-inflector@^3.7.9":
version "3.7.9"
resolved "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-3.7.9.tgz#a1dc7b6635d9415d8dddfee9a09bb5b95190d7f0"
integrity sha512-2LKY5TRUs9h7nE9gQaUUiNV0eLOh5Tr4eJtYp2RGaxeMZhOZhVbbiXc+FV2BPe9bOEpYK3hy678RLBIx0C18nQ==
dependencies:
"@formkit/auto-animate" "^1.0.0-beta.1"
classnames "^2.2.6"