add unisex gender game

This commit is contained in:
lingdocs 2021-09-02 17:09:07 +04:00
parent 0410642492
commit 2fa773ab60
10 changed files with 240 additions and 21 deletions

View File

@ -4,7 +4,7 @@
"private": true, "private": true,
"dependencies": { "dependencies": {
"@fortawesome/fontawesome-free": "^5.15.2", "@fortawesome/fontawesome-free": "^5.15.2",
"@lingdocs/pashto-inflector": "^0.8.3", "@lingdocs/pashto-inflector": "^0.9.3",
"@testing-library/jest-dom": "^4.2.4", "@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2", "@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2", "@testing-library/user-event": "^7.1.2",

View File

@ -16,7 +16,7 @@ const pConsonants = ["ب", "پ", "ت", "ټ", "ث", "ج", "چ", "ح", "خ", "څ",
fetch(process.env.LINGDOCS_DICTIONARY_URL).then(res => res.arrayBuffer()).then(data => { fetch(process.env.LINGDOCS_DICTIONARY_URL).then(res => res.arrayBuffer()).then(data => {
const { entries } = readDictionary(data); const { entries } = readDictionary(data);
const filtered = entries.filter(e => ( const filtered = entries.filter(e => (
e.c === "n. m." && ["ا", "ه", "ي"].includes(e.p.slice(-1)) && (!["u", "h"].includes(e.g.slice(-1))) e.c?.includes("n. m. unisex")
)); ));
const content = `module.exports = [ const content = `module.exports = [
${filtered.reduce((text, entry) => ( ${filtered.reduce((text, entry) => (

View File

@ -56,7 +56,10 @@ export default function({level}: { level: 1 | 2 }) {
? wordPool ? wordPool
: getRandomFromList([wordPool, exceptions]); : getRandomFromList([wordPool, exceptions]);
const gender = getRandomFromList(Object.keys(base)); const gender = getRandomFromList(Object.keys(base));
const typeToUse = getRandomFromList(Object.keys(base[gender])); let typeToUse: string;
do {
typeToUse = getRandomFromList(Object.keys(base[gender]));
} while (!base[gender].length);
const question = getRandomFromList(base[gender][typeToUse]).entry; const question = getRandomFromList(base[gender][typeToUse]).entry;
base[gender][typeToUse] = base[gender][typeToUse].filter(({ entry }) => entry.ts !== question.ts); base[gender][typeToUse] = base[gender][typeToUse].filter(({ entry }) => entry.ts !== question.ts);
yield { yield {

View File

@ -0,0 +1,128 @@
import React, { useState } from "react";
import {
getRandomFromList,
makeProgress,
} from "../lib/game-utils";
import genderColors from "../lib/gender-colors";
import Game from "./Game";
import {
Types as T,
Examples,
defaultTextOptions as opts,
inflectWord,
standardizePashto,
removeAccents,
// pashtoConsonants,
} from "@lingdocs/pashto-inflector";
import words from "../words/nouns-adjs";
import {
firstVariation,
} from "../lib/text-tools";
const nouns = words.filter((w) => w.category === "nouns-unisex").map(x => x.entry);
// type NType = "consonant" | "eyUnstressed" | "eyStressed" | "pashtun" | "withu"
// const types: Record<NType, T.DictionaryEntry[]> = {
// consonant: nouns.filter((w) => pashtoConsonants.includes(w.p.slice(-1))),
// eyUnstressed: nouns.filter((w) => w.f.slice(-2) === "ey"),
// eyStressed: nouns.filter((w) => w.f.slice(-2) === "éy"),
// pashtun: nouns.filter((w) => w.infaf?.includes("aa")),
// withu: nouns.filter((w) => w.infaf?.slice(-1) === "u" && !!w.infaf?.includes("aa")),
// }
const genders: T.Gender[] = ["masc", "fem"];
const amount = 20;
type Question = { entry: T.DictionaryEntry, gender: T.Gender };
export default function() {
function* questions (): Generator<Current<Question>> {
let pool = [...nouns];
for (let i = 0; i < amount; i++) {
// const keys = Object.keys(types) as NType[];
// let type: NType
// do {
// type = getRandomFromList(keys);
// } while (!pool[type].length);
const entry = getRandomFromList(pool);
const gender = getRandomFromList(genders) as T.Gender;
pool = pool.filter((x) => x.ts !== entry.ts);
yield {
progress: makeProgress(i, amount),
question: {
entry,
gender,
},
};
}
}
function Display({ question, callback }: QuestionDisplayProps<Question>) {
function flipGender(g: T.Gender): T.Gender {
return g === "masc" ? "fem" : "masc";
}
const [answer, setAnswer] = useState<string>("");
const inflected = inflectWord(question.entry) as T.UnisexInflections;
const givenGender = question.gender === "masc" ? "masculine" : "feminine";
const requiredGender = question.gender === "fem" ? "masculine" : "feminine";
if (!inflected || !inflected.masc || !inflected.fem) {
return <div>WORD ERROR</div>;
}
function handleInput({ target: { value }}: React.ChangeEvent<HTMLInputElement>) {
setAnswer(value);
}
function handleSubmit(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
const given = standardizePashto(answer.trim());
const correct = inflected[flipGender(question.gender)][0].some((ps) => (
(given === ps.p) || (removeAccents(given) === removeAccents(ps.f))
));
if (correct) {
setAnswer("");
}
callback(correct);
}
return <div>
<div className="pt-2 pb-1 mb-2" style={{ maxWidth: "300px", margin: "0 auto", backgroundColor: genderColors[question.gender === "masc" ? "m" : "f"]}}>
<Examples opts={opts}>{[
{
...inflected[question.gender][0][0],
e: firstVariation(question.entry.e),
}
]}</Examples>
</div>
<div>Is {givenGender}. Make it <span style={{ background: genderColors[requiredGender === "masculine" ? "m" : "f"]}}>{requiredGender}</span>.</div>
<form onSubmit={handleSubmit}>
<div className="my-3" 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>
<button type="submit" className="btn btn-primary">Check</button>
</div>
</form>
</div>
}
function Instructions() {
return <div>
Change the gender of a given word
</div>
}
return <Game
questions={questions}
Display={Display}
timeLimit={125}
Instructions={Instructions}
/>
};

View File

@ -73,15 +73,24 @@ Notice how it does not use the first feminine inflection <InlinePs opts={opts} p
## 3. Words ending in a stressed <InlinePs opts={opts} ps={{ p: "ی", f: "éy" }} /> ## 3. Words ending in a stressed <InlinePs opts={opts} ps={{ p: "ی", f: "éy" }} />
This is very similar to pattern #2, but with the stress on the last syllable the feminine inflection changes.
<InflectionCarousel items={startingWord(words, "ey-stressed-unisex", "لومړی")} /> <InflectionCarousel items={startingWord(words, "ey-stressed-unisex", "لومړی")} />
## 4. Words with the "Pashtun" pattern ## 4. Words with the "Pashtun" pattern
These words are a little irregular but you can see a common patten based around:
- lengthening the 1st masculine inflection with <InlinePs opts={opts} ps={{ p: "ا ـ ـه", f: "aa _ u" }} />
- shortening the other forms and adding the <InlinePs opts={opts} ps={{ p: "ـه", f: "-a" }} />, <InlinePs opts={opts} ps={{ p: "ـې", f: "-e" }} />, <InlinePs opts={opts} ps={{ p: "ـو", f: "-o" }} /> endings
<InflectionCarousel items={startingWord(words, "aanu-unisex", "پښتون")} /> <InflectionCarousel items={startingWord(words, "aanu-unisex", "پښتون")} />
**Note**: Nouns in this pattern will often only use the first inflection for the plural. Adjectives will use the 1st inflection for all 3 reasons. **Note**: Nouns in this pattern will often only use the first inflection for the plural. Adjectives will use the 1st inflection for all 3 reasons.
## 5. Shorter irregular words ## 5. Shorter words that take <InlinePs opts={opts} ps={{ p: "ـه", f: "-u" }} />
These are also a little irregular but instead of lengthening the 1st masculine inflection they compress it as well and take just an <InlinePs opts={opts} ps={{ p: "ـه", f: "-u" }} /> on the end.
<InflectionCarousel items={startingWord(words, "short-irreg-unisex", "غل")} /> <InflectionCarousel items={startingWord(words, "short-irreg-unisex", "غل")} />

View File

@ -10,6 +10,7 @@ import {
import Table from "../../components/Table"; import Table from "../../components/Table";
import Link from "../../components/Link"; import Link from "../../components/Link";
import GenderTable from "../../components/GenderTable"; import GenderTable from "../../components/GenderTable";
import UnisexNounGame from "../../components/UnisexNounGame";
There are many words for people and animals in Pashto that can be used in both masculine and feminine forms. There are many words for people and animals in Pashto that can be used in both masculine and feminine forms.
@ -104,8 +105,6 @@ If the accent comes on the end of the word, the femine form is a little differen
### 4. Words with the "Pashtun" pattern ### 4. Words with the "Pashtun" pattern
Well...
<GenderTable rows={[ <GenderTable rows={[
{ {
masc: { masc: {
@ -173,9 +172,7 @@ Well...
} }
]} /> ]} />
### 5. Shorter irregular words ### 5. Shorter words that take <InlinePs opts={opts} ps={{ p: "ـه", f: "-u" }} />
You get the idea...
<GenderTable rows={[ <GenderTable rows={[
{ {
@ -212,6 +209,10 @@ You get the idea...
} }
]} /> ]} />
**🕹 Here's a game to practice changing the genders of nouns**
<UnisexNounGame />
<!-- <!--
{ {
masc: { masc: {

View File

@ -26,7 +26,6 @@ module.exports = [
// { ts: 1527815845, e: "life" }, // ژوندون // { ts: 1527815845, e: "life" }, // ژوندون
{ ts: 1527815300, e: "rider, mounted" }, // سپور { ts: 1527815300, e: "rider, mounted" }, // سپور
{ ts: 1527819505, e: "being (in a place after returning, coming back etc.)" }, // ستون { ts: 1527819505, e: "being (in a place after returning, coming back etc.)" }, // ستون
{ ts: 1527813293, e: "red; hot" }, // سور
{ ts: 1600080053835, e: "riding, mounted" }, // سور { ts: 1600080053835, e: "riding, mounted" }, // سور
{ ts: 1527813068, e: "cold" }, // سوړ { ts: 1527813068, e: "cold" }, // سوړ
{ ts: 1575924767041, e: "shepherd" }, // شپون { ts: 1575924767041, e: "shepherd" }, // شپون

View File

@ -0,0 +1,79 @@
module.exports = [
{ ts: 1527821744, e: `cook, chef` }, // آشپز - aashpáz
{ ts: 1527812156, e: `officer` }, // افسر - afsar
{ ts: 1591872915426, e: `Afghan (person)` }, // افغانی - afghaanéy
{ ts: 1527815137, e: `instigator, insurgent, terrorist` }, // اورپکی - orpakey
{ ts: 1582853867682, e: `resident` }, // اوسېدونکی - osedóonkey
{ ts: 1527812476, e: `child, offspring` }, // بچی - bachéy
{ ts: 1623044005072, e: `insurrectionist, rebel` }, // بلواګر - balwaagar
{ ts: 1612616237182, e: `Pakistani (person)` }, // پاکستانی - paakistaanéy
{ ts: 1527817965, e: `keeper, one who brings up, raises (cattle etc.)` }, // پالونکی - paaloonkey
{ ts: 1527815197, e: `Pashtun` }, // پښتون - puxtoon
{ ts: 1527819228, e: `inspector, detective, person checking people at the doors etc.` }, // پلټونکی - pulaToonkey
{ ts: 1527820130, e: `adherent, supporter; the outside or further ox in a team of oxes grinding or threshing` }, // پلوی - palawéy
{ ts: 1527815924, e: `customer` }, // پېرودونکی - perodoonkey
{ ts: 1527816431, e: `cousin (of paternal aunt)` }, // ترورزی - trorzéy
{ ts: 1527820820, e: `follower` }, // تعقیبوونکی - ta'qeebawóonkey
{ ts: 1586270915475, e: `mammal` }, // تي لرونکی - tee laroonkey
{ ts: 1613563994424, e: `joker, jester, mocker` }, // ټوقمار - Toqmaar
{ ts: 1610793723568, e: `ram, goat` }, // چېلی - cheléy
{ ts: 1527811466, e: `researcher` }, // څېړونکی - tseRoonkey
{ ts: 1527812795, e: `relative` }, // خپلوان - khpulwaan
{ ts: 1527812802, e: `donkey` }, // خر - khur
{ ts: 1527813282, e: `seller` }, // خرڅوونکی - khartsawóonkey
{ ts: 1527819362, e: `calf (animal)` }, // خوسی - khooséy
{ ts: 1527822535, e: `tailor` }, // خیاط - khayáat
{ ts: 1590052667427, e: `witness` }, // درستی - drustéy, drastéy
{ ts: 1622873938137, e: `crook, swindler, criminal` }, // درغلګر - darghalgar
{ ts: 1527820656, e: `mediator, arbitrator` }, // دریمګړی - driyamgúRey
{ ts: 1614081825855, e: `priest, monk/nun` }, // راهب - raahib
{ ts: 1527813758, e: `student, learner, pupil` }, // زدکوونکی - zdakawóonkey
{ ts: 1527819587, e: `translator` }, // ژباړونکی - jzbaaRoonkey
{ ts: 1527815299, e: `dog` }, // سپی - spéy
{ ts: 1610447830096, e: `calf; bull-calf` }, // سخی - skhey
{ ts: 1527816932, e: `soldier` }, // سرتېری - sărtérey
{ ts: 1527811519, e: `embassador, ambassador` }, // سفیر - safeer
{ ts: 1622366208373, e: `secretary` }, // سکرتر - sakratár
{ ts: 1527820170, e: `singer` }, // سندرغاړی - sandurgháaRey
{ ts: 1566468540788, e: `rabbit` }, // سوی - sooy
{ ts: 1527819801, e: `tourist, sightseer, visitor` }, // سیلانی - seylaanéy
{ ts: 1575924767041, e: `shepherd` }, // شپون - shpoon
{ ts: 1527815279, e: `shepherd` }, // شپونکی - shpoonkey
{ ts: 1527819173, e: `analyst, examiner` }, // شنونکی - shanóonkey
{ ts: 1612614411126, e: `teacher` }, // ښووونکی - xowóonkey
{ ts: 1527815436, e: `tyrant, oppressor, cruel person` }, // ظالم - zaalim
{ ts: 1527818632, e: `twin` }, // غبرګونی - ghbargoney
{ ts: 1527812624, e: `thief` }, // غل - ghul
{ ts: 1613561408232, e: `guilty, at fault` }, // قصوروار - qUsoorwáar
{ ts: 1527812724, e: `of Kabul (a person)` }, // کابلی - kaabuley
{ ts: 1527814715, e: `user` }, // کاروونکی - kaarawoonkey
{ ts: 1527816256, e: `great-grandson` }, // کړوسی - kaRwaséy
{ ts: 1594906790729, e: `child` }, // ککی - kakéy
{ ts: 1527819244, e: `host, hostess; master of house` }, // کوربه - korba
{ ts: 1527812174, e: `neighbour` }, // ګاونډی - gaawanDéy
{ ts: 1579030083953, e: `sinner, sinful` }, // ګناه ګار - gUnaahgáar
{ ts: 1527816249, e: `grandchild` }, // لمسی - lmaséy
{ ts: 1527822661, e: `athlete, player; actor; mischevious, playful (of a child)` }, // لوبغاړی - lobgháaRey
{ ts: 1589885143650, e: `fox` }, // لومبړ - loombáR
{ ts: 1527812043, e: `writer, author` }, // لیکوال - leekwaal
{ ts: 1527820680, e: `crazy, insane, mad person` }, // لېونی - lewanéy
{ ts: 1527812881, e: `child, kid` }, // ماشوم - maashoom
{ ts: 1527814445, e: `assigned, appointed, given orders or istructions (Arabic), authorized, sent on business; officer (as in government worker)` }, // مامور - maamóor
{ ts: 1527818760, e: `civil activist` }, // مدني فاعل - madanee faa'al
{ ts: 1527821523, e: `slave, servant` }, // مریی - mrayéy
{ ts: 1527814159, e: `friend, companion` }, // ملګری - malgúrey
{ ts: 1527820661, e: `mediator, go-between, arbitrator` }, // مېنځګړی - mendzgúRey
{ ts: 1527823403, e: `fan, someone who loves or appreciates someone or something` }, // مینه وال - meenawáal
{ ts: 1527815127, e: `nurse` }, // نرس - nurs
{ ts: 1527816254, e: `grandson` }, // نوسی - nwaséy
{ ts: 1527814806, e: `peer, someone of the same age` }, // همځولی - hamdzoléy ??
{ ts: 1527812684, e: `co-worker, fellow worker, collaborator, aid` }, // همکار - hamkaar
{ ts: 1527811732, e: `artist, performer` }, // هنر مند - hUnarmand
{ ts: 1527821373, e: `deer` }, // هوسی - hoséy
{ ts: 1591027046896, e: `goat` }, // وز - wuz
{ ts: 1611395180139, e: `fellow countryman, person from the same country` }, // وطندار - watandáar
{ ts: 1527811296, e: `lawyer, proxy holder` }, // وکیل - wakeel
{ ts: 1527813585, e: `person, human being, creature` }, // وګړی - wagúRey
{ ts: 1527814672, e: `spokesperson, spokesman, newcaster` }, // ویاند - wayaand
{ ts: 1586454081484, e: `orphan` }, // یتیم - yateem
];

File diff suppressed because one or more lines are too long

View File

@ -1566,10 +1566,10 @@
"@types/yargs" "^15.0.0" "@types/yargs" "^15.0.0"
chalk "^4.0.0" chalk "^4.0.0"
"@lingdocs/pashto-inflector@^0.8.3": "@lingdocs/pashto-inflector@^0.9.3":
version "0.8.3" version "0.9.4"
resolved "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-0.8.3.tgz#427cf38a2c8ae81a65dc8bd0d65445d317e8ad36" resolved "https://npm.lingdocs.com/@lingdocs%2fpashto-inflector/-/pashto-inflector-0.9.4.tgz#a05aa5151ec57550e1364377dff1b593039be76c"
integrity sha512-+8S5fEiJo3fC2/gp+IP09j3NZNBc5NuCV5FOWAGINEmg8NBKDVMa1gXnmuca6nVQsV2G4ZTk3UJyLwizq1RzDg== integrity sha512-sn1TMGf8myoBr0NfRF5JtP//Y3A6cxwhVC8PtrZYgocYWA6lyB3H/R+ZblcUx7TCPwoH/aHIA365oKOpRDNMgw==
dependencies: dependencies:
classnames "^2.2.6" classnames "^2.2.6"
pbf "^3.2.1" pbf "^3.2.1"
@ -9559,9 +9559,9 @@ property-information@^5.0.0, property-information@^5.3.0:
xtend "^4.0.0" xtend "^4.0.0"
protocol-buffers-schema@^3.3.1: protocol-buffers-schema@^3.3.1:
version "3.5.1" version "3.5.2"
resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.5.1.tgz#8388e768d383ac8cbea23e1280dfadb79f4122ad" resolved "https://registry.yarnpkg.com/protocol-buffers-schema/-/protocol-buffers-schema-3.5.2.tgz#38ad35ba768607a5ed2375f8db4c2ecc5ea293c8"
integrity sha512-YVCvdhxWNDP8/nJDyXLuM+UFsuPk4+1PB7WGPVDzm3HTHbzFLxQYeW2iZpS4mmnXrQJGBzt230t/BbEb7PrQaw== integrity sha512-LPzSaBYp/TcbuSlpGwqT5jR9kvJ3Zp5ic2N5c2ybx6XB/lSfEHq2D7ja8AgoxHoMD91wXFALJoXsvshKPuXyew==
proxy-addr@~2.0.5: proxy-addr@~2.0.5:
version "2.0.6" version "2.0.6"
@ -9679,9 +9679,9 @@ raf@^3.4.1:
performance-now "^2.1.0" performance-now "^2.1.0"
rambda@^6.7.0: rambda@^6.7.0:
version "6.7.0" version "6.9.0"
resolved "https://registry.yarnpkg.com/rambda/-/rambda-6.7.0.tgz#50322efdd23a108b61eb6ac4e0868d10dd95b4aa" resolved "https://registry.yarnpkg.com/rambda/-/rambda-6.9.0.tgz#17cd0b0c427295e00e8fe12de5bd63884502a9a4"
integrity sha512-qg2atEwhAS4ipYoNfggkIP7qBUbY2OqdW17n25VqZIz5YC1MIwSpIToQ7XacvqSCZz16efM8Y8QKLx+Js1Sybg== integrity sha512-yosVdGg1hNGkXPzqGiOYNEpXKjEOxzUCg2rB0l+NKdyCaSf4z+i5ojbN0IqDSezMMf71YEglI+ZUTgTffn5afw==
randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0:
version "2.1.0" version "2.1.0"