This commit is contained in:
lingdocs 2022-08-30 19:08:17 +04:00
parent 83654a8276
commit 40089f76a2
9 changed files with 112 additions and 47 deletions

View File

@ -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.1", "@lingdocs/lingdocs-main": "^0.3.1",
"@lingdocs/pashto-inflector": "^3.8.4", "@lingdocs/pashto-inflector": "^3.8.7",
"@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",

View File

@ -16,7 +16,7 @@ import {
import { isImperativeTense, isPerfectTense } from "@lingdocs/pashto-inflector/dist/lib/type-predicates"; import { isImperativeTense, isPerfectTense } from "@lingdocs/pashto-inflector/dist/lib/type-predicates";
import { useState } from "react"; import { useState } from "react";
import Carousel from "./Carousel"; import Carousel from "./Carousel";
import { basicVerbs, intransitivePast } from "../content/verbs/basic-present-verbs"; import { basicVerbs, intransitivePastVerbs } from "../content/verbs/basic-present-verbs";
import { getLength } from "@lingdocs/pashto-inflector/dist/lib/p-text-helpers"; import { getLength } from "@lingdocs/pashto-inflector/dist/lib/p-text-helpers";
import { isThirdPerson } from "@lingdocs/pashto-inflector/dist/lib/phrase-building/vp-tools"; import { isThirdPerson } from "@lingdocs/pashto-inflector/dist/lib/phrase-building/vp-tools";
@ -27,7 +27,7 @@ function BasicVerbShowCase({ opts, tense, passive, ability }: {
ability?: boolean, ability?: boolean,
}) { }) {
const items = isPastTense(tense) const items = isPastTense(tense)
? intransitivePast ? intransitivePastVerbs
: (passive ? basicVerbs.filter(v => v.entry.p !== "کول") : basicVerbs); : (passive ? basicVerbs.filter(v => v.entry.p !== "کول") : basicVerbs);
return <Carousel stickyTitle items={items} render={(item) => { return <Carousel stickyTitle items={items} render={(item) => {
return { return {

View File

@ -14,7 +14,7 @@ export const basicVerbs: T.VerbEntry[] = [
].map(entry => ({ entry })); ].map(entry => ({ entry }));
// @ts-ignore // @ts-ignore
export const intransitivePast: T.VerbEntry[] = [ export const intransitivePastVerbs: T.VerbEntry[] = [
{"ts":1527813573,"i":6809,"p":"رسېدل","f":"rasedul","g":"rasedul","e":"arrive, reached; (fig.) understand, attain to; mature, ripen","c":"v. intrans.","shortIntrans":true,"ec":"arrive"}, {"ts":1527813573,"i":6809,"p":"رسېدل","f":"rasedul","g":"rasedul","e":"arrive, reached; (fig.) understand, attain to; mature, ripen","c":"v. intrans.","shortIntrans":true,"ec":"arrive"},
{"ts":1527812645,"i":10822,"p":"ګرځېدل","f":"gurdzedul","g":"gurdzedul","e":"to walk, wander, turn about; to become, to be","c":"v. intrans.","shortIntrans":true,"ec":"walk"}, {"ts":1527812645,"i":10822,"p":"ګرځېدل","f":"gurdzedul","g":"gurdzedul","e":"to walk, wander, turn about; to become, to be","c":"v. intrans.","shortIntrans":true,"ec":"walk"},
{"ts":1527816495,"i":3470,"p":"تښتېدل","f":"tuxtedul","g":"tuxtedul","e":"to run off, escape, flee","c":"v. intrans.","shortIntrans":true,"ec":"escape"}, {"ts":1527816495,"i":3470,"p":"تښتېدل","f":"tuxtedul","g":"tuxtedul","e":"to run off, escape, flee","c":"v. intrans.","shortIntrans":true,"ec":"escape"},

View File

@ -54,13 +54,13 @@ function ChapterDisplay({ chapter, user, handleClick, expanded }: {
return <div key={id}> return <div key={id}>
<div className="d-flex flex-row justify-content-between align-items-center"> <div className="d-flex flex-row justify-content-between align-items-center">
<div> <div>
<h4 className="my-4 clickable" onClick={() => handleTitleClick(id)}> <h5 className="my-3 clickable" onClick={() => handleTitleClick(id)}>
<i className={`fas fa-caret-${open ? "down" : "right"}`}></i> {title} <i className={`fas fa-caret-${open ? "down" : "right"}`}></i> {title}
{` `} {` `}
</h4> </h5>
</div> </div>
<div> <div>
<h4> <h4 className={done ? "clickable" : ""}>
{done ? "✅" {done ? "✅"
: :
<Link to={studyLink}>{"📚"}</Link> <Link to={studyLink}>{"📚"}</Link>

View File

@ -41,6 +41,18 @@ export const imperativeVerbGame = makeGameRecord(
"/verbs/imperative-verbs/", "/verbs/imperative-verbs/",
(id, link) => () => <VerbGame id={id} level="imperative" link={link} /> (id, link) => () => <VerbGame id={id} level="imperative" link={link} />
); );
export const intransitivePerfectivePastVerbGame = makeGameRecord(
"Write the intransitive simple past verb",
"intransitive-perfective-past-verbs-write",
"/verbs/past-verbs/#past-tense-with-transitive-verbs-",
(id, link) => () => <VerbGame id={id} level="intransitivePerfectivePast" link={link} />
);
export const intransitiveImperfectivePastVerbGame = makeGameRecord(
"Write the intransitive continuous past verb",
"transitive-imperfective-past-verbs-write",
"/verbs/past-verbs/#past-tense-with-transitive-verbs-",
(id, link) => () => <VerbGame id={id} level="intransitiveImperfectivePast" link={link} />
);
export const nounGenderGame1 = makeGameRecord( export const nounGenderGame1 = makeGameRecord(
"Identify Noun Genders - Level 1", "Identify Noun Genders - Level 1",
@ -170,6 +182,8 @@ const games: { chapter: string, items: GameRecord[] }[] = [
subjunctiveVerbGame, subjunctiveVerbGame,
futureVerbGame, futureVerbGame,
imperativeVerbGame, imperativeVerbGame,
intransitiveImperfectivePastVerbGame,
intransitivePerfectivePastVerbGame,
], ],
} }
]; ];

View File

@ -34,6 +34,8 @@ import { isThirdPerson } from "@lingdocs/pashto-inflector/dist/lib/phrase-buildi
import { maybeShuffleArray } from "../../lib/shuffle-array"; import { maybeShuffleArray } from "../../lib/shuffle-array";
import { getVerbFromBlocks } from "@lingdocs/pashto-inflector/dist/lib/phrase-building/blocks-utils"; import { getVerbFromBlocks } from "@lingdocs/pashto-inflector/dist/lib/phrase-building/blocks-utils";
import { baParticle } from "@lingdocs/pashto-inflector/dist/lib/grammar-units"; import { baParticle } from "@lingdocs/pashto-inflector/dist/lib/grammar-units";
import { intransitivePastVerbs } from "../../content/verbs/basic-present-verbs";
import { makePool } from "../../lib/pool";
const kidsColor = "#017BFE"; const kidsColor = "#017BFE";
@ -66,45 +68,47 @@ const nouns: T.NounEntry[] = [
{"ts":1527812661,"i":13938,"p":"هلک","f":"halík, halúk","g":"halik,haluk","e":"boy, young lad","c":"n. m. anim."}, {"ts":1527812661,"i":13938,"p":"هلک","f":"halík, halúk","g":"halik,haluk","e":"boy, young lad","c":"n. m. anim."},
].filter(tp.isNounEntry); ].filter(tp.isNounEntry);
const pronounTypes = [ const persons = [
[T.Person.FirstSingMale, T.Person.FirstSingFemale], T.Person.FirstSingMale,
[T.Person.SecondSingMale, T.Person.SecondSingFemale], T.Person.FirstSingFemale,
[T.Person.ThirdSingMale], T.Person.SecondSingMale,
[T.Person.ThirdSingFemale], T.Person.SecondSingFemale,
[T.Person.FirstPlurMale, T.Person.FirstPlurFemale], T.Person.ThirdSingMale,
[T.Person.SecondPlurMale, T.Person.SecondPlurFemale], T.Person.ThirdSingFemale,
[T.Person.ThirdPlurMale, T.Person.ThirdPlurFemale], T.Person.FirstPlurMale,
T.Person.FirstPlurFemale,
T.Person.SecondPlurMale,
T.Person.SecondPlurFemale,
T.Person.ThirdPlurMale,
T.Person.ThirdPlurFemale,
]; ];
const secondPersonPronounTypes = [ const secondPersons = [
[T.Person.SecondSingMale, T.Person.SecondSingFemale], T.Person.SecondSingMale,
[T.Person.SecondPlurMale, T.Person.SecondPlurFemale], T.Person.SecondSingFemale,
T.Person.SecondPlurMale,
T.Person.SecondPlurFemale,
]; ];
type VerbGameLevel = "presentVerb" | "subjunctiveVerb" | "futureVerb" | "imperative"; type VerbGameLevel = "presentVerb" | "subjunctiveVerb"
| "futureVerb" | "imperative" | "intransitivePerfectivePast" | "intransitiveImperfectivePast";
export default function VerbGame({ id, link, level }: { export default function VerbGame({ id, link, level }: {
id: string, id: string,
link: string, link: string,
level: VerbGameLevel, level: VerbGameLevel,
}) { }) {
const poolBase = level === "imperative"
? secondPersonPronounTypes
: pronounTypes;
function* questions (): Generator<Current<Question>> { function* questions (): Generator<Current<Question>> {
let pool = [...poolBase]; const personPool = makePool(level === "imperative"
function getRandPersFromPool(): T.Person { ? secondPersons
let person: T.Person; : persons
do { );
person = randomPerson(); const verbPool = makePool(
// eslint-disable-next-line level.includes("intransitive")
} while (!pool.some(p => p.includes(person))); ? intransitivePastVerbs
pool = pool.filter(p => !p.includes(person)); : verbs,
if (pool.length === 0) { 30,
pool = poolBase; );
}
return person;
}
function makeRandomNoun(): T.NounSelection { function makeRandomNoun(): T.NounSelection {
const n = makeNounSelection(randFromArray(nouns), undefined); const n = makeNounSelection(randFromArray(nouns), undefined);
return { return {
@ -137,8 +141,8 @@ export default function VerbGame({ id, link, level }: {
distance: randFromArray(["far", "near", "far"]), distance: randFromArray(["far", "near", "far"]),
}; };
} }
const verb = randFromArray(verbs); const verb = verbPool();
const subj = getRandPersFromPool(); const subj = personPool();
let obj: T.Person; let obj: T.Person;
do { do {
obj = randomPerson(); obj = randomPerson();
@ -184,9 +188,6 @@ export default function VerbGame({ id, link, level }: {
setAnswer(value); setAnswer(value);
} }
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => { const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
if ("situation" in question) {
return;
}
e.preventDefault(); e.preventDefault();
const correct = comparePs(answer, getVerbPs(question.rendered)) const correct = comparePs(answer, getVerbPs(question.rendered))
&& (withBa === verbHasBa(question.rendered)); && (withBa === verbHasBa(question.rendered));
@ -347,6 +348,10 @@ function levelToDescription(level: VerbGameLevel): string {
? "subjunctive" ? "subjunctive"
: level === "futureVerb" : level === "futureVerb"
? "imperfective future or perfective future" ? "imperfective future or perfective future"
: level === "intransitivePerfectivePast"
? "simple past intransitive"
: level === "intransitiveImperfectivePast"
? "continuous past intransitive"
: "imperfective imperative or perfective imperative"; : "imperfective imperative or perfective imperative";
} }
@ -357,8 +362,12 @@ function levelToTense(level: VerbGameLevel): T.VerbTense | T.ImperativeTense {
? level ? level
: level === "futureVerb" : level === "futureVerb"
? randFromArray(["perfectiveFuture", "imperfectiveFuture"]) ? randFromArray(["perfectiveFuture", "imperfectiveFuture"])
// : level === "imperative" : level === "imperative"
: randFromArray(["perfectiveImperative", "imperfectiveImperative"]); ? randFromArray(["perfectiveImperative", "imperfectiveImperative"])
: level.includes("ImperfectivePast")
? "imperfectivePast"
// : level.includes("perfectivePast")
: "perfectivePast";
} }
function makeVPS({ verb, subject, object, tense }: { function makeVPS({ verb, subject, object, tense }: {
@ -371,6 +380,7 @@ function makeVPS({ verb, subject, object, tense }: {
const transitivity = (vps.verb.transitivity === "transitive" && vps.verb.canChangeTransitivity) const transitivity = (vps.verb.transitivity === "transitive" && vps.verb.canChangeTransitivity)
? "grammatically transitive" ? "grammatically transitive"
: vps.verb.transitivity; : vps.verb.transitivity;
console.log({ transitivity });
return { return {
...vps, ...vps,
verb: { verb: {

View File

@ -53,6 +53,8 @@ export function comparePs(input: string, answer: T.SingleOrLengthOpts<T.PsString
if (Array.isArray(answer)) { if (Array.isArray(answer)) {
return answer.some(a => comparePs(input, a)); return answer.some(a => comparePs(input, a));
} }
const stand = standardizePhonetics(standardizePashto(input)).trim(); const stand = standardizePhonetics(
standardizePashto(input)
).trim();
return stand === answer.p || compareF(stand, answer.f); return stand === answer.p || compareF(stand, answer.f);
} }

39
src/lib/pool.ts Normal file
View File

@ -0,0 +1,39 @@
import { randFromArray } from "@lingdocs/pashto-inflector";
/**
*
* @param poolBase an array of things you want to use as the pool to pick from
* @param removalLaxity If set, thery will be a n% chance that the pick will NOT
* be removed after use. Defaults to 0, meaning that every time an item is picked
* it is removed from the. 100 means that items will never be removed from the pool.
* @returns
*/
export function makePool<P>(poolBase: P[], removalLaxity = 0): () => P {
let pool = [...poolBase];
function shouldStillKeepIt() {
return Math.random() < (removalLaxity / 100);
}
function pickRandomFromPool(): P {
// Pick an item from the pool;
const pick = randFromArray(pool);
// Remove the (first occurance of) the item from the pool
// This step might be skipped if the removal laxity is set
if (removalLaxity && !shouldStillKeepIt()) {
const index = pool.findIndex(v => matches(v, pick))
if (index === -1) throw new Error("could not find pick from pool");
pool.splice(index, 1);
// If the pool is empty, reset it
if (pool.length === 0) {
pool = [...poolBase];
}
}
return pick;
}
return pickRandomFromPool;
}
function matches(a: unknown, b: unknown): boolean {
return JSON.stringify(a) === JSON.stringify(b);
}

View File

@ -1803,10 +1803,10 @@
rambda "^6.7.0" rambda "^6.7.0"
react-select "^5.2.2" react-select "^5.2.2"
"@lingdocs/pashto-inflector@^3.8.4": "@lingdocs/pashto-inflector@^3.8.7":
version "3.8.4" version "3.8.7"
resolved "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-3.8.4.tgz#2a29b04c541f3d12842ae2dabc3bc1e71a1b77ad" resolved "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-3.8.7.tgz#9f9a28718f82620a74c4d7732232bd716cf0fd85"
integrity sha512-YVH+LFX4UslcQnNfYbmE9vX+bsq/LFylnxk3lEMLDLRW/abRmWlcPcElJr2wXYm3VR5uoLCK463ulS7IhQoUeQ== integrity sha512-rVjQole0oQpsGBZOqQ7btO80mbL04JhHC6z21G0vLYAswOe4OFdnQyBfKztMclYKiJV2vdtWLXpjjdIPt+Ypbg==
dependencies: dependencies:
"@formkit/auto-animate" "^1.0.0-beta.1" "@formkit/auto-animate" "^1.0.0-beta.1"
classnames "^2.2.6" classnames "^2.2.6"